Introduce a VM Traps mechanism and refactor Watchdog to use it.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Feb 2017 01:20:54 +0000 (01:20 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Feb 2017 01:20:54 +0000 (01:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=168842

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Currently, the traps mechanism is only used for the JSC watchdog, and for
asynchronous termination requests (which is currently only used for worker
threads termination).

This first cut of the traps mechanism still relies on polling from DFG and FTL
code.  This is done to keep the patch as small as possible.  The work to do
a non-polling version of the traps mechanism for DFG and FTL code is deferred to
another patch.

In this patch, worker threads still need to set the VM::m_needAsynchronousTerminationSupport
flag to enable the traps polling in the DFG and FTL code.  When we have the
non-polling version of the DFG and FTL traps mechanism, we can remove the use of
the VM::m_needAsynchronousTerminationSupport flag.

Note: this patch also separates asynchronous termination support from the JSC
watchdog.  This separation allows us to significantly simplify the locking
requirements in the watchdog code, and make it easier to reason about its
correctness.

* CMakeLists.txt:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeList.json:
* bytecode/BytecodeUseDef.h:
(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dumpBytecode):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::emitLoopHint):
(JSC::BytecodeGenerator::emitCheckTraps):
(JSC::BytecodeGenerator::emitWatchdog): Deleted.
* bytecompiler/BytecodeGenerator.h:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.cpp:
(JSC::DFG::capabilityLevel):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGNodeType.h:
* dfg/DFGPredictionPropagationPhase.cpp:
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCheckTraps):
* dfg/DFGSpeculativeJIT.h:
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckTraps):
(JSC::FTL::DFG::LowerDFGToB3::compileCheckWatchdogTimer): Deleted.
* interpreter/Interpreter.cpp:
(JSC::Interpreter::executeProgram):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::execute):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
* jit/JIT.h:
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_check_traps):
(JSC::JIT::emitSlow_op_check_traps):
(JSC::JIT::emit_op_watchdog): Deleted.
(JSC::JIT::emitSlow_op_watchdog): Deleted.
* jit/JITOperations.cpp:
* jit/JITOperations.h:
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LLIntSlowPaths.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/VM.cpp:
(JSC::VM::~VM):
(JSC::VM::ensureWatchdog):
(JSC::VM::handleTraps):
* runtime/VM.h:
(JSC::VM::ownerThread):
(JSC::VM::needTrapHandling):
(JSC::VM::needTrapHandlingAddress):
(JSC::VM::notifyNeedTermination):
(JSC::VM::notifyNeedWatchdogCheck):
(JSC::VM::needAsynchronousTerminationSupport):
(JSC::VM::setNeedAsynchronousTerminationSupport):
* runtime/VMInlines.h:
(JSC::VM::shouldTriggerTermination): Deleted.
* runtime/VMTraps.cpp: Added.
(JSC::VMTraps::fireTrap):
(JSC::VMTraps::takeTrap):
* runtime/VMTraps.h: Added.
(JSC::VMTraps::needTrapHandling):
(JSC::VMTraps::needTrapHandlingAddress):
(JSC::VMTraps::hasTrapForEvent):
(JSC::VMTraps::setTrapForEvent):
(JSC::VMTraps::clearTrapForEvent):
* runtime/Watchdog.cpp:
(JSC::Watchdog::Watchdog):
(JSC::Watchdog::setTimeLimit):
(JSC::Watchdog::shouldTerminate):
(JSC::Watchdog::enteredVM):
(JSC::Watchdog::exitedVM):
(JSC::Watchdog::startTimer):
(JSC::Watchdog::stopTimer):
(JSC::Watchdog::willDestroyVM):
(JSC::Watchdog::terminateSoon): Deleted.
(JSC::Watchdog::shouldTerminateSlow): Deleted.
* runtime/Watchdog.h:
(JSC::Watchdog::shouldTerminate): Deleted.
(JSC::Watchdog::timerDidFireAddress): Deleted.

Source/WebCore:

No new tests needed because this is a re-implementation of existing functionality.

* bindings/js/WorkerScriptController.cpp:
(WebCore::WorkerScriptController::WorkerScriptController):
(WebCore::WorkerScriptController::scheduleExecutionTermination):

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

43 files changed:
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/BytecodeList.json
Source/JavaScriptCore/bytecode/BytecodeUseDef.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGCapabilities.cpp
Source/JavaScriptCore/dfg/DFGClobberize.h
Source/JavaScriptCore/dfg/DFGDoesGC.cpp
Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGSafeToExecute.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
Source/JavaScriptCore/ftl/FTLCapabilities.cpp
Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITOpcodes.cpp
Source/JavaScriptCore/jit/JITOperations.cpp
Source/JavaScriptCore/jit/JITOperations.h
Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
Source/JavaScriptCore/llint/LLIntSlowPaths.h
Source/JavaScriptCore/llint/LowLevelInterpreter.asm
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/llint/LowLevelInterpreter64.asm
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/runtime/VMInlines.h
Source/JavaScriptCore/runtime/VMTraps.cpp [new file with mode: 0644]
Source/JavaScriptCore/runtime/VMTraps.h [new file with mode: 0644]
Source/JavaScriptCore/runtime/Watchdog.cpp
Source/JavaScriptCore/runtime/Watchdog.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/WorkerScriptController.cpp

index 3944998..7975df0 100644 (file)
@@ -904,6 +904,7 @@ set(JavaScriptCore_SOURCES
     runtime/TypeofType.cpp
     runtime/VM.cpp
     runtime/VMEntryScope.cpp
+    runtime/VMTraps.cpp
     runtime/VarOffset.cpp
     runtime/Watchdog.cpp
     runtime/WeakMapConstructor.cpp
index 3c2aa83..1614f57 100644 (file)
@@ -1,3 +1,132 @@
+2017-02-27  Mark Lam  <mark.lam@apple.com>
+
+        Introduce a VM Traps mechanism and refactor Watchdog to use it.
+        https://bugs.webkit.org/show_bug.cgi?id=168842
+
+        Reviewed by Filip Pizlo.
+
+        Currently, the traps mechanism is only used for the JSC watchdog, and for
+        asynchronous termination requests (which is currently only used for worker
+        threads termination).
+
+        This first cut of the traps mechanism still relies on polling from DFG and FTL
+        code.  This is done to keep the patch as small as possible.  The work to do
+        a non-polling version of the traps mechanism for DFG and FTL code is deferred to
+        another patch.
+
+        In this patch, worker threads still need to set the VM::m_needAsynchronousTerminationSupport
+        flag to enable the traps polling in the DFG and FTL code.  When we have the
+        non-polling version of the DFG and FTL traps mechanism, we can remove the use of
+        the VM::m_needAsynchronousTerminationSupport flag.
+
+        Note: this patch also separates asynchronous termination support from the JSC
+        watchdog.  This separation allows us to significantly simplify the locking
+        requirements in the watchdog code, and make it easier to reason about its
+        correctness.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/BytecodeList.json:
+        * bytecode/BytecodeUseDef.h:
+        (JSC::computeUsesForBytecodeOffset):
+        (JSC::computeDefsForBytecodeOffset):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dumpBytecode):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        (JSC::BytecodeGenerator::emitLoopHint):
+        (JSC::BytecodeGenerator::emitCheckTraps):
+        (JSC::BytecodeGenerator::emitWatchdog): Deleted.
+        * bytecompiler/BytecodeGenerator.h:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGCapabilities.cpp:
+        (JSC::DFG::capabilityLevel):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCheckTraps):
+        * dfg/DFGSpeculativeJIT.h:
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckTraps):
+        (JSC::FTL::DFG::LowerDFGToB3::compileCheckWatchdogTimer): Deleted.
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::executeProgram):
+        (JSC::Interpreter::executeCall):
+        (JSC::Interpreter::executeConstruct):
+        (JSC::Interpreter::execute):
+        * jit/JIT.cpp:
+        (JSC::JIT::privateCompileMainPass):
+        (JSC::JIT::privateCompileSlowCases):
+        * jit/JIT.h:
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_check_traps):
+        (JSC::JIT::emitSlow_op_check_traps):
+        (JSC::JIT::emit_op_watchdog): Deleted.
+        (JSC::JIT::emitSlow_op_watchdog): Deleted.
+        * jit/JITOperations.cpp:
+        * jit/JITOperations.h:
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LLIntSlowPaths.h:
+        * llint/LowLevelInterpreter.asm:
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/VM.cpp:
+        (JSC::VM::~VM):
+        (JSC::VM::ensureWatchdog):
+        (JSC::VM::handleTraps):
+        * runtime/VM.h:
+        (JSC::VM::ownerThread):
+        (JSC::VM::needTrapHandling):
+        (JSC::VM::needTrapHandlingAddress):
+        (JSC::VM::notifyNeedTermination):
+        (JSC::VM::notifyNeedWatchdogCheck):
+        (JSC::VM::needAsynchronousTerminationSupport):
+        (JSC::VM::setNeedAsynchronousTerminationSupport):
+        * runtime/VMInlines.h:
+        (JSC::VM::shouldTriggerTermination): Deleted.
+        * runtime/VMTraps.cpp: Added.
+        (JSC::VMTraps::fireTrap):
+        (JSC::VMTraps::takeTrap):
+        * runtime/VMTraps.h: Added.
+        (JSC::VMTraps::needTrapHandling):
+        (JSC::VMTraps::needTrapHandlingAddress):
+        (JSC::VMTraps::hasTrapForEvent):
+        (JSC::VMTraps::setTrapForEvent):
+        (JSC::VMTraps::clearTrapForEvent):
+        * runtime/Watchdog.cpp:
+        (JSC::Watchdog::Watchdog):
+        (JSC::Watchdog::setTimeLimit):
+        (JSC::Watchdog::shouldTerminate):
+        (JSC::Watchdog::enteredVM):
+        (JSC::Watchdog::exitedVM):
+        (JSC::Watchdog::startTimer):
+        (JSC::Watchdog::stopTimer):
+        (JSC::Watchdog::willDestroyVM):
+        (JSC::Watchdog::terminateSoon): Deleted.
+        (JSC::Watchdog::shouldTerminateSlow): Deleted.
+        * runtime/Watchdog.h:
+        (JSC::Watchdog::shouldTerminate): Deleted.
+        (JSC::Watchdog::timerDidFireAddress): Deleted.
+
 2017-02-27  Commit Queue  <commit-queue@webkit.org>
 
         Unreviewed, rolling out r213019.
index a5d9f8b..5a70b0e 100644 (file)
                FE6491391D78F3AF00A694D4 /* ExceptionScope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE6491381D78F3A300A694D4 /* ExceptionScope.cpp */; };
                FE68C6371B90DE040042BCB3 /* MacroAssemblerPrinter.h in Headers */ = {isa = PBXBuildFile; fileRef = FE68C6361B90DDD90042BCB3 /* MacroAssemblerPrinter.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE68C6381B90DE0B0042BCB3 /* MacroAssemblerPrinter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE68C6351B90DDD90042BCB3 /* MacroAssemblerPrinter.cpp */; };
+               FE6F56DE1E64EAD600D17801 /* VMTraps.h in Headers */ = {isa = PBXBuildFile; fileRef = FE6F56DD1E64E92000D17801 /* VMTraps.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               FE6F56DF1E64EADB00D17801 /* VMTraps.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE6F56DC1E64E92000D17801 /* VMTraps.cpp */; };
                FE7BA60F1A1A7CEC00F1F7B4 /* HeapVerifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */; };
                FE7BA6101A1A7CEC00F1F7B4 /* HeapVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */; settings = {ATTRIBUTES = (Private, ); }; };
                FE7C41961B97FC4B00F4D598 /* PingPongStackOverflowTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEDA50D41B97F442009A3B4F /* PingPongStackOverflowTest.cpp */; };
                FE6491381D78F3A300A694D4 /* ExceptionScope.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionScope.cpp; sourceTree = "<group>"; };
                FE68C6351B90DDD90042BCB3 /* MacroAssemblerPrinter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MacroAssemblerPrinter.cpp; sourceTree = "<group>"; };
                FE68C6361B90DDD90042BCB3 /* MacroAssemblerPrinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerPrinter.h; sourceTree = "<group>"; };
+               FE6F56DC1E64E92000D17801 /* VMTraps.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VMTraps.cpp; sourceTree = "<group>"; };
+               FE6F56DD1E64E92000D17801 /* VMTraps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VMTraps.h; sourceTree = "<group>"; };
                FE7BA60D1A1A7CEC00F1F7B4 /* HeapVerifier.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HeapVerifier.cpp; sourceTree = "<group>"; };
                FE7BA60E1A1A7CEC00F1F7B4 /* HeapVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeapVerifier.h; sourceTree = "<group>"; };
                FE80C1961D775B27008510C0 /* CatchScope.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CatchScope.h; sourceTree = "<group>"; };
                                FE5932A5183C5A2600A1ECCC /* VMEntryScope.cpp */,
                                FE5932A6183C5A2600A1ECCC /* VMEntryScope.h */,
                                FE90BB3A1B7CF64E006B3F03 /* VMInlines.h */,
+                               FE6F56DC1E64E92000D17801 /* VMTraps.cpp */,
+                               FE6F56DD1E64E92000D17801 /* VMTraps.h */,
                                FED94F2B171E3E2300BE77A4 /* Watchdog.cpp */,
                                FED94F2C171E3E2300BE77A4 /* Watchdog.h */,
                                14BFCE6810CDB1FC00364CCE /* WeakGCMap.h */,
                                E3FF75331D9CEA1800C7E16D /* DOMJITGetterSetter.h in Headers */,
                                E35CA1541DBC3A5C00F83516 /* DOMJITHeapRange.h in Headers */,
                                E3C08E3C1DA41B810039478F /* DOMJITPatchpoint.h in Headers */,
+                               FE6F56DE1E64EAD600D17801 /* VMTraps.h in Headers */,
                                E37AD83C1DA4928600F3D412 /* DOMJITPatchpointParams.h in Headers */,
                                E37AD83D1DA4928600F3D412 /* DOMJITReg.h in Headers */,
                                E350708A1DC49BBF0089BCD6 /* DOMJITSignature.h in Headers */,
                                149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
                                A5FC84B31D1DDAD9006B5C46 /* DebuggerLocation.cpp in Sources */,
                                A5A1A0951D8CB341004C2EB8 /* DebuggerParseData.cpp in Sources */,
+                               FE6F56DF1E64EADB00D17801 /* VMTraps.cpp in Sources */,
                                0F2D4DDD19832D34007D4B19 /* DebuggerScope.cpp in Sources */,
                                2A7A58EF1808A4C40020BDF7 /* DeferGC.cpp in Sources */,
                                0FC712DE17CD8779008CC93C /* DeferredCompilationCallback.cpp in Sources */,
index ada4429..0827af9 100644 (file)
             { "name" : "op_create_rest", "length": 4 },
             { "name" : "op_get_rest_length", "length": 3 },
             { "name" : "op_yield", "length" : 4 },
-            { "name" : "op_watchdog", "length" : 1 },
+            { "name" : "op_check_traps", "length" : 1 },
             { "name" : "op_log_shadow_chicken_prologue", "length" : 2},
             { "name" : "op_log_shadow_chicken_tail", "length" : 3}
         ]
index 99b9394..e097e10 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -53,7 +53,7 @@ void computeUsesForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_create_direct_arguments:
     case op_create_cloned_arguments:
     case op_get_rest_length:
-    case op_watchdog:
+    case op_check_traps:
     case op_get_argument:
         return;
     case op_assert:
@@ -359,7 +359,7 @@ void computeDefsForBytecodeOffset(Block* codeBlock, OpcodeID opcodeID, Instructi
     case op_profile_control_flow:
     case op_put_to_arguments:
     case op_set_function_name:
-    case op_watchdog:
+    case op_check_traps:
     case op_log_shadow_chicken_prologue:
     case op_log_shadow_chicken_tail:
     case op_yield:
index 05f6a6d..cd97f34 100644 (file)
@@ -1386,8 +1386,8 @@ void CodeBlock::dumpBytecode(
             printLocationAndOp(out, exec, location, it, "loop_hint");
             break;
         }
-        case op_watchdog: {
-            printLocationAndOp(out, exec, location, it, "watchdog");
+        case op_check_traps: {
+            printLocationAndOp(out, exec, location, it, "check_traps");
             break;
         }
         case op_log_shadow_chicken_prologue: {
index 538767d..88be265 100644 (file)
@@ -195,7 +195,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ProgramNode* programNode, UnlinkedP
 
     allocateAndEmitScope();
 
-    emitWatchdog();
+    emitCheckTraps();
 
     const FunctionStack& functionStack = programNode->functionStack();
 
@@ -329,7 +329,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
 
     allocateAndEmitScope();
 
-    emitWatchdog();
+    emitCheckTraps();
     
     if (functionNameIsInScope(functionNode->ident(), functionNode->functionMode())) {
         ASSERT(parseMode != SourceParseMode::GeneratorBodyMode);
@@ -761,7 +761,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, EvalNode* evalNode, UnlinkedEvalCod
 
     allocateAndEmitScope();
 
-    emitWatchdog();
+    emitCheckTraps();
     
     const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack();
     for (size_t i = 0; i < functionStack.size(); ++i)
@@ -846,7 +846,7 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, ModuleProgramNode* moduleProgramNod
 
     allocateAndEmitScope();
 
-    emitWatchdog();
+    emitCheckTraps();
     
     m_calleeRegister.setIndex(CallFrameSlot::callee);
 
@@ -1269,13 +1269,13 @@ void BytecodeGenerator::emitEnter()
 void BytecodeGenerator::emitLoopHint()
 {
     emitOpcode(op_loop_hint);
-    emitWatchdog();
+    emitCheckTraps();
 }
 
-void BytecodeGenerator::emitWatchdog()
+void BytecodeGenerator::emitCheckTraps()
 {
-    if (vm()->watchdog())
-        emitOpcode(op_watchdog);
+    if (vm()->watchdog() || vm()->needAsynchronousTerminationSupport())
+        emitOpcode(op_check_traps);
 }
 
 void BytecodeGenerator::retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index)
index 0fbee0a..26c1d25 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2009, 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
  * Copyright (C) 2012 Igalia, S.L.
  *
@@ -704,7 +704,7 @@ namespace JSC {
         void emitJumpIfNotFunctionApply(RegisterID* cond, Label& target);
 
         void emitEnter();
-        void emitWatchdog();
+        void emitCheckTraps();
 
         RegisterID* emitHasIndexedProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName);
         RegisterID* emitHasStructureProperty(RegisterID* dst, RegisterID* base, RegisterID* propertyName, RegisterID* enumerator);
index 54f0ab6..0d2e929 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -2914,7 +2914,7 @@ bool AbstractInterpreter<AbstractStateType>::executeEffects(unsigned clobberLimi
         m_state.setStructureClobberState(StructuresAreWatched);
         break;
 
-    case CheckWatchdogTimer:
+    case CheckTraps:
     case LogShadowChickenPrologue:
     case LogShadowChickenTail:
         break;
index 85374b5..3a454dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -5383,9 +5383,9 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             NEXT_OPCODE(op_loop_hint);
         }
         
-        case op_watchdog: {
-            addToGraph(CheckWatchdogTimer);
-            NEXT_OPCODE(op_watchdog); 
+        case op_check_traps: {
+            addToGraph(CheckTraps);
+            NEXT_OPCODE(op_check_traps);
         }
             
         case op_create_lexical_environment: {
index b786d55..fde32e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -187,7 +187,7 @@ CapabilityLevel capabilityLevel(OpcodeID opcodeID, CodeBlock* codeBlock, Instruc
     case op_jngreater:
     case op_jngreatereq:
     case op_loop_hint:
-    case op_watchdog:
+    case op_check_traps:
     case op_ret:
     case op_end:
     case op_new_object:
index 4df48a2..c9c1940 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1411,7 +1411,7 @@ void clobberize(Graph& graph, Node* node, const ReadFunctor& read, const WriteFu
         return;
         
     case CountExecution:
-    case CheckWatchdogTimer:
+    case CheckTraps:
         read(InternalState);
         write(InternalState);
         return;
index d5eab16..c7aae3d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -190,7 +190,7 @@ bool doesGC(Graph& graph, Node* node)
     case Throw:
     case CountExecution:
     case ForceOSRExit:
-    case CheckWatchdogTimer:
+    case CheckTraps:
     case StringFromCharCode:
     case MapHash:
     case GetMapBucket:
index 3ce6494..4edea23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1868,7 +1868,7 @@ private:
         case ForceOSRExit:
         case CheckBadCell:
         case CheckNotEmpty:
-        case CheckWatchdogTimer:
+        case CheckTraps:
         case Unreachable:
         case ExtractOSREntryLocal:
         case LoopHint:
index 05d2065..1357e69 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -391,8 +391,8 @@ namespace JSC { namespace DFG {
     /* flow. */\
     macro(BottomValue, NodeResultJS) \
     \
-    /* Checks the watchdog timer. If the timer has fired, we call operation operationHandleWatchdogTimer*/ \
-    macro(CheckWatchdogTimer, NodeMustGenerate) \
+    /* Checks for VM traps. If there is a trap, we call operation operationHandleTraps */ \
+    macro(CheckTraps, NodeMustGenerate) \
     /* Write barriers */\
     macro(StoreBarrier, NodeMustGenerate) \
     macro(FencedStoreBarrier, NodeMustGenerate) \
index 7a081fe..82566df 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1101,7 +1101,7 @@ private:
         case Phantom:
         case Check:
         case PutGlobalVariable:
-        case CheckWatchdogTimer:
+        case CheckTraps:
         case LogShadowChickenPrologue:
         case LogShadowChickenTail:
         case Unreachable:
index 4bcc68b..b97ebca 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -317,7 +317,7 @@ bool safeToExecute(AbstractStateType& state, Graph& graph, Node* node)
     case ThrowStaticError:
     case CountExecution:
     case ForceOSRExit:
-    case CheckWatchdogTimer:
+    case CheckTraps:
     case LogShadowChickenPrologue:
     case LogShadowChickenTail:
     case StringFromCharCode:
index 1954cf4..03ddbd1 100644 (file)
@@ -1895,6 +1895,17 @@ void SpeculativeJIT::linkOSREntries(LinkBuffer& linkBuffer)
             dumpContext.dump(WTF::dataFile());
     }
 }
+    
+void SpeculativeJIT::compileCheckTraps(Node*)
+{
+    GPRTemporary unused(this);
+    GPRReg unusedGPR = unused.gpr();
+
+    JITCompiler::Jump needTrapHandling = m_jit.branchTest8(JITCompiler::NonZero,
+        JITCompiler::AbsoluteAddress(m_jit.vm()->needTrapHandlingAddress()));
+
+    addSlowPathGenerator(slowPathCall(needTrapHandling, this, operationHandleTraps, unusedGPR));
+}
 
 void SpeculativeJIT::compileDoublePutByVal(Node* node, SpeculateCellOperand& base, SpeculateStrictInt32Operand& property)
 {
index 226ee31..dbe69b7 100644 (file)
@@ -762,6 +762,8 @@ public:
         return lastNode->op() == Branch && lastNode->child1() == m_currentNode ? m_block->size() - 1 : UINT_MAX;
     }
     
+    void compileCheckTraps(Node*);
+
     void compileMovHint(Node*);
     void compileMovHintAndCheck(Node*);
 
index d91ddd4..f0cf92c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2011 Intel Corporation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -5543,17 +5543,9 @@ void SpeculativeJIT::compile(Node* node)
         emitInvalidationPoint(node);
         break;
 
-    case CheckWatchdogTimer: {
-        ASSERT(m_jit.vm()->watchdog());
-        GPRTemporary unused(this);
-        GPRReg unusedGPR = unused.gpr();
-        
-        JITCompiler::Jump timerDidFire = m_jit.branchTest8(JITCompiler::NonZero,
-            JITCompiler::AbsoluteAddress(m_jit.vm()->watchdog()->timerDidFireAddress()));
-        
-        addSlowPathGenerator(slowPathCall(timerDidFire, this, operationHandleWatchdogTimer, unusedGPR));
+    case CheckTraps:
+        compileCheckTraps(node);
         break;
-    }
 
     case CountExecution:
         m_jit.add64(TrustedImm32(1), MacroAssembler::AbsoluteAddress(node->executionCounter()->address()));
index 848fa4a..5f61475 100644 (file)
@@ -5327,17 +5327,9 @@ void SpeculativeJIT::compile(Node* node)
         emitInvalidationPoint(node);
         break;
 
-    case CheckWatchdogTimer: {
-        ASSERT(m_jit.vm()->watchdog());
-        GPRTemporary unused(this);
-        GPRReg unusedGPR = unused.gpr();
-
-        JITCompiler::Jump timerDidFire = m_jit.branchTest8(JITCompiler::NonZero,
-            JITCompiler::AbsoluteAddress(m_jit.vm()->watchdog()->timerDidFireAddress()));
-
-        addSlowPathGenerator(slowPathCall(timerDidFire, this, operationHandleWatchdogTimer, unusedGPR));
+    case CheckTraps:
+        compileCheckTraps(node);
         break;
-    }
 
     case Phantom:
     case Check:
index 1a151ec..c6f3839 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -134,7 +134,7 @@ inline CapabilityLevel canCompile(Node* node)
     case CheckBadCell:
     case CheckNotEmpty:
     case CheckStringIdent:
-    case CheckWatchdogTimer:
+    case CheckTraps:
     case StringCharCodeAt:
     case StringFromCharCode:
     case AllocatePropertyStorage:
index 2e733e0..7c96fe0 100644 (file)
@@ -1021,8 +1021,8 @@ private:
         case MaterializeCreateActivation:
             compileMaterializeCreateActivation();
             break;
-        case CheckWatchdogTimer:
-            compileCheckWatchdogTimer();
+        case CheckTraps:
+            compileCheckTraps();
             break;
         case CreateRest:
             compileCreateRest();
@@ -8983,20 +8983,20 @@ private:
         setJSValue(activation);
     }
 
-    void compileCheckWatchdogTimer()
+    void compileCheckTraps()
     {
-        LBasicBlock timerDidFire = m_out.newBlock();
+        LBasicBlock needTrapHandling = m_out.newBlock();
         LBasicBlock continuation = m_out.newBlock();
         
-        LValue state = m_out.load8ZeroExt32(m_out.absolute(vm().watchdog()->timerDidFireAddress()));
+        LValue state = m_out.load8ZeroExt32(m_out.absolute(vm().needTrapHandlingAddress()));
         m_out.branch(m_out.isZero32(state),
-            usually(continuation), rarely(timerDidFire));
+            usually(continuation), rarely(needTrapHandling));
 
-        LBasicBlock lastNext = m_out.appendTo(timerDidFire, continuation);
+        LBasicBlock lastNext = m_out.appendTo(needTrapHandling, continuation);
 
         lazySlowPath(
             [=] (const Vector<Location>&) -> RefPtr<LazySlowPath::Generator> {
-                return createLazyCallGenerator(operationHandleWatchdogTimer, InvalidGPRReg);
+                return createLazyCallGenerator(operationHandleTraps, InvalidGPRReg);
             });
         m_out.jump(continuation);
         
index 4402ef2..f28d837 100644 (file)
@@ -860,8 +860,10 @@ failedJSONP:
         codeBlock = jsCast<ProgramCodeBlock*>(tempCodeBlock);
     }
 
-    if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
-        return throwTerminatedExecutionException(callFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(callFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     if (scope->structure()->isUncacheableDictionary())
         scope->flattenDictionaryObject(vm);
@@ -918,8 +920,10 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
     } else
         newCodeBlock = 0;
 
-    if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
-        return throwTerminatedExecutionException(callFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(callFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     ProtoCallFrame protoCallFrame;
     protoCallFrame.init(newCodeBlock, function, thisValue, argsCount, args.data());
@@ -981,8 +985,10 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
     } else
         newCodeBlock = 0;
 
-    if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
-        return throwTerminatedExecutionException(callFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(callFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     ProtoCallFrame protoCallFrame;
     protoCallFrame.init(newCodeBlock, constructor, newTarget, argsCount, args.data());
@@ -1043,8 +1049,10 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
 
     StackStats::CheckPoint stackCheckPoint;
 
-    if (UNLIKELY(vm.shouldTriggerTermination(closure.oldCallFrame)))
-        return throwTerminatedExecutionException(closure.oldCallFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(closure.oldCallFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     // Execute the code:
     JSValue result = closure.functionExecutable->generatedJITCodeForCall()->execute(&vm, closure.protoCallFrame);
@@ -1144,8 +1152,10 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
         }
     }
 
-    if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
-        return throwTerminatedExecutionException(callFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(callFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     ASSERT(codeBlock->numParameters() == 1); // 1 parameter for 'this'.
 
@@ -1183,8 +1193,10 @@ JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* cal
         codeBlock = jsCast<ModuleProgramCodeBlock*>(tempCodeBlock);
     }
 
-    if (UNLIKELY(vm.shouldTriggerTermination(callFrame)))
-        return throwTerminatedExecutionException(callFrame, throwScope);
+    if (UNLIKELY(vm.needTrapHandling())) {
+        vm.handleTraps(callFrame);
+        RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
+    }
 
     if (scope->structure()->isUncacheableDictionary())
         scope->flattenDictionaryObject(vm);
index e74219b..a853f99 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2009, 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -328,7 +328,7 @@ void JIT::privateCompileMainPass()
         DEFINE_OP(op_jngreatereq)
         DEFINE_OP(op_jtrue)
         DEFINE_OP(op_loop_hint)
-        DEFINE_OP(op_watchdog)
+        DEFINE_OP(op_check_traps)
         DEFINE_OP(op_lshift)
         DEFINE_OP(op_mod)
         DEFINE_OP(op_mov)
@@ -504,7 +504,7 @@ void JIT::privateCompileSlowCases()
         DEFINE_SLOWCASE_OP(op_jngreater)
         DEFINE_SLOWCASE_OP(op_jngreatereq)
         DEFINE_SLOWCASE_OP(op_loop_hint)
-        DEFINE_SLOWCASE_OP(op_watchdog)
+        DEFINE_SLOWCASE_OP(op_check_traps)
         DEFINE_SLOWCASE_OP(op_lshift)
         DEFINE_SLOWCASE_OP(op_mod)
         DEFINE_SLOWCASE_OP(op_mul)
index d8e74d4..cb44dce 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -530,7 +530,7 @@ namespace JSC {
         void emit_op_jngreatereq(Instruction*);
         void emit_op_jtrue(Instruction*);
         void emit_op_loop_hint(Instruction*);
-        void emit_op_watchdog(Instruction*);
+        void emit_op_check_traps(Instruction*);
         void emit_op_lshift(Instruction*);
         void emit_op_mod(Instruction*);
         void emit_op_mov(Instruction*);
@@ -638,7 +638,7 @@ namespace JSC {
         void emitSlow_op_jngreatereq(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_loop_hint(Instruction*, Vector<SlowCaseEntry>::iterator&);
-        void emitSlow_op_watchdog(Instruction*, Vector<SlowCaseEntry>::iterator&);
+        void emitSlow_op_check_traps(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_lshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&);
         void emitSlow_op_mul(Instruction*, Vector<SlowCaseEntry>::iterator&);
index 337e0b7..cc395c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, 2012-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2009-2017 Apple Inc. All rights reserved.
  * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -943,17 +943,15 @@ void JIT::emit_op_throw_static_error(Instruction* currentInstruction)
     slowPathCall.call();
 }
 
-void JIT::emit_op_watchdog(Instruction*)
+void JIT::emit_op_check_traps(Instruction*)
 {
-    ASSERT(m_vm->watchdog());
-    addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_vm->watchdog()->timerDidFireAddress())));
+    addSlowCase(branchTest8(NonZero, AbsoluteAddress(m_vm->needTrapHandlingAddress())));
 }
 
-void JIT::emitSlow_op_watchdog(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
+void JIT::emitSlow_op_check_traps(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
 {
-    ASSERT(m_vm->watchdog());
     linkSlowCase(iter);
-    callOperation(operationHandleWatchdogTimer);
+    callOperation(operationHandleTraps);
 }
 
 void JIT::emit_op_new_regexp(Instruction* currentInstruction)
index a1d4e73..255cc11 100644 (file)
@@ -1205,18 +1205,14 @@ EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr
 }
 
 // The only reason for returning an UnusedPtr (instead of void) is so that we can reuse the
-// existing DFG slow path generator machinery when creating the slow path for CheckWatchdogTimer
+// existing DFG slow path generator machinery when creating the slow path for CheckTraps
 // in the DFG. If a DFG slow path generator that supports a void return type is added in the
 // future, we can switch to using that then.
-UnusedPtr JIT_OPERATION operationHandleWatchdogTimer(ExecState* exec)
+UnusedPtr JIT_OPERATION operationHandleTraps(ExecState* exec)
 {
     VM& vm = exec->vm();
     NativeCallFrameTracer tracer(&vm, exec);
-    auto scope = DECLARE_THROW_SCOPE(vm);
-
-    if (UNLIKELY(vm.shouldTriggerTermination(exec)))
-        throwException(exec, scope, createTerminatedExecutionException(&vm));
-
+    vm.handleTraps(exec);
     return nullptr;
 }
 
index d72ffbe..318c0ed 100644 (file)
@@ -384,7 +384,7 @@ EncodedJSValue JIT_OPERATION operationNewAsyncFunctionWithInvalidatedReallocatio
 void JIT_OPERATION operationSetFunctionName(ExecState*, JSCell*, EncodedJSValue) WTF_INTERNAL;
 JSCell* JIT_OPERATION operationNewObject(ExecState*, Structure*) WTF_INTERNAL;
 EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState*, void*) WTF_INTERNAL;
-UnusedPtr JIT_OPERATION operationHandleWatchdogTimer(ExecState*) WTF_INTERNAL;
+UnusedPtr JIT_OPERATION operationHandleTraps(ExecState*) WTF_INTERNAL;
 void JIT_OPERATION operationThrow(ExecState*, EncodedJSValue) WTF_INTERNAL;
 void JIT_OPERATION operationDebug(ExecState*, int32_t) WTF_INTERNAL;
 #if ENABLE(DFG_JIT)
index c5e8181..37bc463 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -1494,13 +1494,11 @@ LLINT_SLOW_PATH_DECL(slow_path_throw)
     LLINT_THROW(LLINT_OP_C(1).jsValue());
 }
 
-LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer)
+LLINT_SLOW_PATH_DECL(slow_path_handle_traps)
 {
     LLINT_BEGIN_NO_SET_PC();
-    ASSERT(vm.watchdog());
-    if (UNLIKELY(vm.shouldTriggerTermination(exec)))
-        LLINT_THROW(createTerminatedExecutionException(&vm));
-    LLINT_RETURN_TWO(0, exec);
+    vm.handleTraps(exec);
+    LLINT_RETURN_TWO(throwScope.exception(), exec);
 }
 
 LLINT_SLOW_PATH_DECL(slow_path_debug)
index d76138c..84fb03e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2014, 2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2011-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -118,7 +118,7 @@ LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_tear_off_arguments);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_throw);
-LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_handle_watchdog_timer);
+LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_handle_traps);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_debug);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_handle_exception);
 LLINT_SLOW_PATH_HIDDEN_DECL(slow_path_get_from_scope);
index 6b49964..e8e2db8 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+# Copyright (C) 2011-2017 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -1544,19 +1544,17 @@ _llint_op_loop_hint:
     dispatch(1)
 
 
-_llint_op_watchdog:
+_llint_op_check_traps:
     traceExecution()
     loadp CodeBlock[cfr], t1
     loadp CodeBlock::m_vm[t1], t1
-    loadp VM::m_watchdog[t1], t0
-    btpnz t0, .handleWatchdogTimer
-.afterWatchdogTimerCheck:
+    loadb VM::m_traps+VMTraps::m_needTrapHandling[t1], t0
+    btpnz t0, .handleTraps
+.afterHandlingTraps:
     dispatch(1)
-.handleWatchdogTimer:
-    loadb Watchdog::m_timerDidFire[t0], t0
-    btbz t0, .afterWatchdogTimerCheck
-    callWatchdogTimerHandler(.throwHandler)
-    jmp .afterWatchdogTimerCheck
+.handleTraps:
+    callTrapHandler(.throwHandler)
+    jmp .afterHandlingTraps
 .throwHandler:
     jmp _llint_throw_from_slow_path_trampoline
 
index d9fed6b..f31b926 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+# Copyright (C) 2011-2017 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -377,11 +377,11 @@ macro callCallSlowPath(slowPath, action)
     action(r0, r1)
 end
 
-macro callWatchdogTimerHandler(throwHandler)
+macro callTrapHandler(throwHandler)
     storei PC, ArgumentCount + TagOffset[cfr]
     move cfr, a0
     move PC, a1
-    cCall2(_llint_slow_path_handle_watchdog_timer)
+    cCall2(_llint_slow_path_handle_traps)
     btpnz r0, throwHandler
     loadi ArgumentCount + TagOffset[cfr], PC
 end
index 0881d37..298ce77 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2016 Apple Inc. All rights reserved.
+# Copyright (C) 2011-2017 Apple Inc. All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
@@ -347,12 +347,12 @@ macro callCallSlowPath(slowPath, action)
     action(r0, r1)
 end
 
-macro callWatchdogTimerHandler(throwHandler)
+macro callTrapHandler(throwHandler)
     storei PC, ArgumentCount + TagOffset[cfr]
     prepareStateForCCall()
     move cfr, a0
     move PC, a1
-    cCall2(_llint_slow_path_handle_watchdog_timer)
+    cCall2(_llint_slow_path_handle_traps)
     btpnz r0, throwHandler
     loadi ArgumentCount + TagOffset[cfr], PC
 end
index a50f9db..d2e2fc4 100644 (file)
@@ -98,6 +98,7 @@
 #include "StrictEvalActivation.h"
 #include "StrongInlines.h"
 #include "StructureInlines.h"
+#include "ThrowScope.h"
 #include "TypeProfiler.h"
 #include "TypeProfilerLog.h"
 #include "UnlinkedCodeBlock.h"
@@ -356,6 +357,8 @@ VM::VM(VMType vmType, HeapType heapType)
 
 VM::~VM()
 {
+    if (UNLIKELY(m_watchdog))
+        m_watchdog->willDestroyVM(this);
     VMInspector::instance().remove(this);
 
     // Never GC, ever again.
@@ -459,7 +462,7 @@ VM*& VM::sharedInstanceInternal()
 Watchdog& VM::ensureWatchdog()
 {
     if (!m_watchdog) {
-        m_watchdog = adoptRef(new Watchdog());
+        m_watchdog = adoptRef(new Watchdog(this));
         
         // 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
@@ -943,4 +946,28 @@ void VM::verifyExceptionCheckNeedIsSatisfied(unsigned recursionDepth, ExceptionE
 }
 #endif
 
+void VM::handleTraps(ExecState* exec)
+{
+    auto scope = DECLARE_THROW_SCOPE(*this);
+
+    ASSERT(needTrapHandling());
+    while (needTrapHandling()) {
+        auto trapEventType = m_traps.takeTopPriorityTrap();
+        switch (trapEventType) {
+        case VMTraps::NeedWatchdogCheck:
+            ASSERT(m_watchdog);
+            if (LIKELY(!m_watchdog->shouldTerminate(exec)))
+                continue;
+            FALLTHROUGH;
+
+        case VMTraps::NeedTermination:
+            JSC::throwException(exec, scope, createTerminatedExecutionException(this));
+            return;
+
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+}
+
 } // namespace JSC
index 732b26e..de2b4c9 100644 (file)
@@ -56,6 +56,7 @@
 #include "TemplateRegistryKeyTable.h"
 #include "ThunkGenerators.h"
 #include "VMEntryRecord.h"
+#include "VMTraps.h"
 #include "Watchpoint.h"
 #include <wtf/Bag.h>
 #include <wtf/BumpPointerAllocator.h>
@@ -614,6 +615,8 @@ public:
     std::thread::id exclusiveThread() const { return m_apiLock->exclusiveThread(); }
     void setExclusiveThread(std::thread::id threadId) { m_apiLock->setExclusiveThread(threadId); }
 
+    std::thread::id ownerThread() const { return m_apiLock->ownerThread(); }
+
     JS_EXPORT_PRIVATE void resetDateCache();
 
     RegExpCache* regExpCache() { return m_regExpCache; }
@@ -664,8 +667,6 @@ public:
     void setGlobalConstRedeclarationShouldThrow(bool globalConstRedeclarationThrow) { m_globalConstRedeclarationShouldThrow = globalConstRedeclarationThrow; }
     ALWAYS_INLINE bool globalConstRedeclarationShouldThrow() const { return m_globalConstRedeclarationShouldThrow; }
 
-    inline bool shouldTriggerTermination(ExecState*);
-
     void setShouldBuildPCToCodeOriginMapping() { m_shouldBuildPCToCodeOriginMapping = true; }
     bool shouldBuilderPCToCodeOriginMapping() const { return m_shouldBuildPCToCodeOriginMapping; }
 
@@ -676,6 +677,17 @@ public:
     template<typename Func>
     void logEvent(CodeBlock*, const char* summary, const Func& func);
 
+    void handleTraps(ExecState*);
+
+    bool needTrapHandling() { return m_traps.needTrapHandling(); }
+    void* needTrapHandlingAddress() { return m_traps.needTrapHandlingAddress(); }
+
+    void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
+    void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); }
+
+    bool needAsynchronousTerminationSupport() const { return m_needAsynchronousTerminationSupport; }
+    void setNeedAsynchronousTerminationSupport() { m_needAsynchronousTerminationSupport = true; }
+
 private:
     friend class LLIntOffsetsExtractor;
 
@@ -760,6 +772,7 @@ private:
     DeletePropertyMode m_deletePropertyMode { DeletePropertyMode::Default };
     bool m_globalConstRedeclarationShouldThrow { true };
     bool m_shouldBuildPCToCodeOriginMapping { false };
+    bool m_needAsynchronousTerminationSupport { false };
     std::unique_ptr<CodeCache> m_codeCache;
     std::unique_ptr<BuiltinExecutables> m_builtinExecutables;
     HashMap<String, RefPtr<WatchpointSet>> m_impurePropertyWatchpointSets;
@@ -771,6 +784,7 @@ private:
     unsigned m_controlFlowProfilerEnabledCount;
     Deque<std::unique_ptr<QueuedTask>> m_microtaskQueue;
     MallocPtr<EncodedJSValue> m_exceptionFuzzBuffer;
+    VMTraps m_traps;
     RefPtr<Watchdog> m_watchdog;
     std::unique_ptr<HeapProfiler> m_heapProfiler;
 #if ENABLE(SAMPLING_PROFILER)
index 4001e2d..5a77619 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (C) 2015-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -51,13 +51,6 @@ bool VM::isSafeToRecurseSoft() const
     return safe;
 }
 
-bool VM::shouldTriggerTermination(ExecState* exec)
-{
-    if (!watchdog())
-        return false;
-    return watchdog()->shouldTerminate(exec);
-}
-
 template<typename Func>
 void VM::logEvent(CodeBlock* codeBlock, const char* summary, const Func& func)
 {
diff --git a/Source/JavaScriptCore/runtime/VMTraps.cpp b/Source/JavaScriptCore/runtime/VMTraps.cpp
new file mode 100644 (file)
index 0000000..581e4ab
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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 "VMTraps.h"
+
+namespace JSC {
+
+void VMTraps::fireTrap(VMTraps::EventType eventType)
+{
+    auto locker = holdLock(m_lock);
+    setTrapForEvent(locker, eventType);
+}
+
+bool VMTraps::takeTrap(VMTraps::EventType eventType)
+{
+    auto locker = holdLock(m_lock);
+    if (hasTrapForEvent(locker, eventType)) {
+        clearTrapForEvent(locker, eventType);
+        return true;
+    }
+    return false;
+}
+
+auto VMTraps::takeTopPriorityTrap() -> EventType
+{
+    for (int i = 0; i < NumberOfEventTypes; ++i) {
+        EventType eventType = static_cast<EventType>(i);
+        if (takeTrap(eventType))
+            return eventType;
+    }
+    return Invalid;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/VMTraps.h b/Source/JavaScriptCore/runtime/VMTraps.h
new file mode 100644 (file)
index 0000000..32cbaaf
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <wtf/Lock.h>
+#include <wtf/Locker.h>
+
+namespace JSC {
+
+class VM;
+
+class VMTraps {
+public:
+    enum EventType {
+        // Sorted in servicing priority order from highest to lowest.
+        NeedTermination,
+        NeedWatchdogCheck,
+        NumberOfEventTypes, // This entry must be last in this list.
+        Invalid
+    };
+
+    bool needTrapHandling() { return m_needTrapHandling; }
+    void* needTrapHandlingAddress() { return &m_needTrapHandling; }
+
+    JS_EXPORT_PRIVATE void fireTrap(EventType);
+
+    bool takeTrap(EventType);
+    EventType takeTopPriorityTrap();
+
+private:
+    VM& vm() const;
+
+    bool hasTrapForEvent(Locker<Lock>&, EventType eventType)
+    {
+        ASSERT(eventType < NumberOfEventTypes);
+        return (m_trapsBitField & (1 << eventType));
+    }
+    void setTrapForEvent(Locker<Lock>&, EventType eventType)
+    {
+        ASSERT(eventType < NumberOfEventTypes);
+        m_trapsBitField |= (1 << eventType);
+    }
+    void clearTrapForEvent(Locker<Lock>&, EventType eventType)
+    {
+        ASSERT(eventType < NumberOfEventTypes);
+        m_trapsBitField &= ~(1 << eventType);
+    }
+
+    Lock m_lock;
+    union {
+        uint8_t m_needTrapHandling { false };
+        uint8_t m_trapsBitField;
+    };
+
+    friend class LLIntOffsetsExtractor;
+};
+
+} // namespace JSC
index f6004e6..d1afa3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,8 +40,8 @@ static std::chrono::microseconds currentWallClockTime()
     return std::chrono::duration_cast<std::chrono::microseconds>(steadyTimeSinceEpoch);
 }
 
-Watchdog::Watchdog()
-    : m_timerDidFire(false)
+Watchdog::Watchdog(VM* vm)
+    : m_vm(vm)
     , m_timeLimit(noTimeLimit)
     , m_cpuDeadline(noTimeLimit)
     , m_wallClockDeadline(noTimeLimit)
@@ -55,7 +55,7 @@ Watchdog::Watchdog()
 void Watchdog::setTimeLimit(std::chrono::microseconds limit,
     ShouldTerminateCallback callback, void* data1, void* data2)
 {
-    LockHolder locker(m_lock);
+    ASSERT(m_vm->ownerThread() == std::this_thread::get_id());
 
     m_timeLimit = limit;
     m_callback = callback;
@@ -63,27 +63,14 @@ void Watchdog::setTimeLimit(std::chrono::microseconds limit,
     m_callbackData2 = data2;
 
     if (m_hasEnteredVM && hasTimeLimit())
-        startTimer(locker, m_timeLimit);
-}
-
-JS_EXPORT_PRIVATE void Watchdog::terminateSoon()
-{
-    LockHolder locker(m_lock);
-
-    m_timeLimit = std::chrono::microseconds(0);
-    m_cpuDeadline = std::chrono::microseconds(0);
-    m_wallClockDeadline = std::chrono::microseconds(0);
-    m_timerDidFire = true;
+        startTimer(m_timeLimit);
 }
 
-bool Watchdog::shouldTerminateSlow(ExecState* exec)
+bool Watchdog::shouldTerminate(ExecState* exec)
 {
+    ASSERT(m_vm->ownerThread() == std::this_thread::get_id());
+    // FIXME: Will unindent the following before landing. Leaving indented for now to minimize the code diff.
     {
-        LockHolder locker(m_lock);
-
-        ASSERT(m_timerDidFire);
-        m_timerDidFire = false;
-
         if (currentWallClockTime() < m_wallClockDeadline)
             return false; // Just a stale timer firing. Nothing to do.
 
@@ -94,7 +81,7 @@ bool Watchdog::shouldTerminateSlow(ExecState* exec)
         auto cpuTime = currentCPUTime();
         if (cpuTime < m_cpuDeadline) {
             auto remainingCPUTime = m_cpuDeadline - cpuTime;
-            startTimer(locker, remainingCPUTime);
+            startTimer(remainingCPUTime);
             return false;
         }
     }
@@ -109,9 +96,8 @@ bool Watchdog::shouldTerminateSlow(ExecState* exec)
     if (needsTermination)
         return true;
 
+    // FIXME: Will unindent the following before landing. Leaving indented for now to minimize the code diff.
     {
-        LockHolder locker(m_lock);
-
         // 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),
@@ -125,7 +111,7 @@ bool Watchdog::shouldTerminateSlow(ExecState* exec)
         ASSERT(m_hasEnteredVM);
         bool callbackAlreadyStartedTimer = (m_cpuDeadline != noTimeLimit);
         if (hasTimeLimit() && !callbackAlreadyStartedTimer)
-            startTimer(locker, m_timeLimit);
+            startTimer(m_timeLimit);
     }
     return false;
 }
@@ -138,23 +124,21 @@ bool Watchdog::hasTimeLimit()
 void Watchdog::enteredVM()
 {
     m_hasEnteredVM = true;
-    if (hasTimeLimit()) {
-        LockHolder locker(m_lock);
-        startTimer(locker, m_timeLimit);
-    }
+    if (hasTimeLimit())
+        startTimer(m_timeLimit);
 }
 
 void Watchdog::exitedVM()
 {
     ASSERT(m_hasEnteredVM);
-    LockHolder locker(m_lock);
-    stopTimer(locker);
+    stopTimer();
     m_hasEnteredVM = false;
 }
 
-void Watchdog::startTimer(LockHolder&, std::chrono::microseconds timeLimit)
+void Watchdog::startTimer(std::chrono::microseconds timeLimit)
 {
     ASSERT(m_hasEnteredVM);
+    ASSERT(m_vm->ownerThread() == std::this_thread::get_id());
     ASSERT(hasTimeLimit());
     ASSERT(timeLimit <= m_timeLimit);
 
@@ -167,21 +151,32 @@ void Watchdog::startTimer(LockHolder&, std::chrono::microseconds timeLimit)
         return; // Wait for the current active timer to expire before starting a new one.
 
     // 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_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), [this] {
-        {
-            LockHolder locker(m_lock);
-            m_timerDidFire = true;
-        }
-        deref();
+    // We need to ensure that the Watchdog outlives the timer.
+    // For the same reason, the timer may also outlive the VM that the Watchdog operates on.
+    // So, we always need to null check m_vm before using it. The VM will notify the Watchdog
+    // via willDestroyVM() before it goes away.
+    RefPtr<Watchdog> protectedThis = this;
+    m_timerQueue->dispatchAfter(std::chrono::nanoseconds(timeLimit), [this, protectedThis] {
+        LockHolder locker(m_lock);
+        if (m_vm)
+            m_vm->notifyNeedWatchdogCheck();
     });
 }
 
-void Watchdog::stopTimer(LockHolder&)
+void Watchdog::stopTimer()
 {
+    ASSERT(m_hasEnteredVM);
+    ASSERT(m_vm->ownerThread() == std::this_thread::get_id());
     m_cpuDeadline = noTimeLimit;
 }
 
+void Watchdog::willDestroyVM(VM* vm)
+{
+    LockHolder locker(m_lock);
+    ASSERT_UNUSED(vm, m_vm == vm);
+    m_vm = nullptr;
+}
+
 } // namespace JSC
index 6e863a0..2933611 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -40,49 +40,32 @@ class Watchdog : public WTF::ThreadSafeRefCounted<Watchdog> {
 public:
     class Scope;
 
-    Watchdog();
+    Watchdog(VM*);
+    void willDestroyVM(VM*);
 
     typedef bool (*ShouldTerminateCallback)(ExecState*, void* data1, void* data2);
     void setTimeLimit(std::chrono::microseconds limit, ShouldTerminateCallback = 0, void* data1 = 0, void* data2 = 0);
-    JS_EXPORT_PRIVATE void terminateSoon();
 
-    bool shouldTerminate(ExecState* exec)
-    {
-        if (!m_timerDidFire)
-            return false;
-        return shouldTerminateSlow(exec);
-    }
+    bool shouldTerminate(ExecState*);
 
     bool hasTimeLimit();
     void enteredVM();
     void exitedVM();
 
-    void* timerDidFireAddress() { return &m_timerDidFire; }
-
     static const std::chrono::microseconds noTimeLimit;
 
 private:
-    void startTimer(LockHolder&, std::chrono::microseconds timeLimit);
-    void stopTimer(LockHolder&);
-
-    bool shouldTerminateSlow(ExecState*);
+    void startTimer(std::chrono::microseconds timeLimit);
+    void stopTimer();
 
-    // 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
-    // (probably from another thread) but is only cleared in the script thread.
-    bool m_timerDidFire;
+    Lock m_lock; // Guards access to m_vm.
+    VM* m_vm;
 
     std::chrono::microseconds m_timeLimit;
 
     std::chrono::microseconds m_cpuDeadline;
     std::chrono::microseconds m_wallClockDeadline;
 
-    // Writes to m_timerDidFire and m_timeLimit, and Reads+Writes to m_cpuDeadline and m_wallClockDeadline
-    // must be guarded by this lock.
-    Lock m_lock;
-
     bool m_hasEnteredVM { false };
 
     ShouldTerminateCallback m_callback;
index 2e1f886..7003219 100644 (file)
@@ -1,3 +1,16 @@
+2017-02-27  Mark Lam  <mark.lam@apple.com>
+
+        Introduce a VM Traps mechanism and refactor Watchdog to use it.
+        https://bugs.webkit.org/show_bug.cgi?id=168842
+
+        Reviewed by Filip Pizlo.
+
+        No new tests needed because this is a re-implementation of existing functionality.
+
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::WorkerScriptController):
+        (WebCore::WorkerScriptController::scheduleExecutionTermination):
+
 2017-02-27  Andy Estes  <aestes@apple.com>
 
         [Cocoa] Rename FileMac.mm to FileCocoa.mm
index 230af90..8dd8333 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008, 2016 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2008-2017 Apple Inc. All Rights Reserved.
  * Copyright (C) 2011, 2012 Google Inc. All Rights Reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,6 @@
 #include <runtime/Exception.h>
 #include <runtime/ExceptionHelpers.h>
 #include <runtime/JSLock.h>
-#include <runtime/Watchdog.h>
 
 using namespace JSC;
 
@@ -52,7 +51,7 @@ WorkerScriptController::WorkerScriptController(WorkerGlobalScope* workerGlobalSc
     , m_workerGlobalScopeWrapper(*m_vm)
 {
     m_vm->heap.acquireAccess(); // It's not clear that we have good discipline for heap access, so turn it on permanently.
-    m_vm->ensureWatchdog();
+    m_vm->setNeedAsynchronousTerminationSupport();
     JSVMClientData::initNormalWorld(m_vm.get());
 }
 
@@ -157,9 +156,7 @@ void WorkerScriptController::scheduleExecutionTermination()
     // accurately reflect that state when called from another thread.
     LockHolder locker(m_scheduledTerminationMutex);
     m_isTerminatingExecution = true;
-
-    ASSERT(m_vm->watchdog());
-    m_vm->watchdog()->terminateSoon();
+    m_vm->notifyNeedTermination();
 }
 
 bool WorkerScriptController::isTerminatingExecution() const