<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[213652] trunk/Source</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/213652">213652</a></dd>
<dt>Author</dt> <dd>mark.lam@apple.com</dd>
<dt>Date</dt> <dd>2017-03-09 11:08:46 -0800 (Thu, 09 Mar 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make the VM Traps mechanism non-polling for the DFG and FTL.
https://bugs.webkit.org/show_bug.cgi?id=168920
&lt;rdar://problem/30738588&gt;

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

1. Added a ENABLE(SIGNAL_BASED_VM_TRAPS) configuration in Platform.h.
   This is currently only enabled for OS(DARWIN) and ENABLE(JIT). 
2. Added assembler functions for overwriting an instruction with a breakpoint.
3. Added a new JettisonDueToVMTraps jettison reason.
4. Added CodeBlock and DFG::CommonData utility functions for over-writing
   invalidation points with breakpoint instructions.
5. The BytecodeGenerator now emits the op_check_traps bytecode unconditionally.
6. Remove the JSC_alwaysCheckTraps option because of (4) above.
   For ports that don't ENABLE(SIGNAL_BASED_VM_TRAPS), we'll force
   Options::usePollingTraps() to always be true.  This makes the VMTraps
   implementation fall back to using polling based traps only.

7. Make VMTraps support signal based traps.

Some design and implementation details of signal based VM traps:

- The implementation makes use of 2 signal handlers for SIGUSR1 and SIGTRAP.

- VMTraps::fireTrap() will set the flag for the requested trap and instantiate
  a SignalSender.  The SignalSender will send SIGUSR1 to the mutator thread that
  we want to trap, and check for the occurence of one of the following events:

  a. VMTraps::handleTraps() has been called for the requested trap, or

  b. the VM is inactive and is no longer executing any JS code.  We determine
     this to be the case if the thread no longer owns the JSLock and the VM's
     entryScope is null.

     Note: the thread can relinquish the JSLock while the VM's entryScope is not
     null.  This happens when the thread calls JSLock::dropAllLocks() before
     calling a host function that may block on IO (or whatever).  For our purpose,
     this counts as the VM still running JS code, and VM::fireTrap() will still
     be waiting.

  If the SignalSender does not see either of these events, it will sleep for a
  while and then re-send SIGUSR1 and check for the events again.  When it sees
  one of these events, it will consider the mutator to have received the trap
  request.

- The SIGUSR1 handler will try to insert breakpoints at the invalidation points
  in the DFG/FTL codeBlock at the top of the stack.  This allows the mutator
  thread to break (with a SIGTRAP) exactly at an invalidation point, where it's
  safe to jettison the codeBlock.

  Note: we cannot have the requester thread (that called VMTraps::fireTrap())
  insert the breakpoint instructions itself.  This is because we need the
  register state of the the mutator thread (that we want to trap in) in order to
  find the codeBlocks that we wish to insert the breakpoints in.  Currently,
  we don't have a generic way for the requester thread to get the register state
  of another thread.

- The SIGTRAP handler will check to see if it is trapping on a breakpoint at an
  invalidation point.  If so, it will jettison the codeBlock and adjust the PC
  to re-execute the invalidation OSR exit off-ramp.  After the OSR exit, the
  baseline JIT code will eventually reach an op_check_traps and call
  VMTraps::handleTraps().

  If the handler is not trapping at an invalidation point, then it must be
  observing an assertion failure (which also uses the breakpoint instruction).
  In this case, the handler will defer to the default SIGTRAP handler and crash.

- The reason we need the SignalSender is because SignalSender::send() is called
  from another thread in a loop, so that VMTraps::fireTrap() can return sooner.
  send() needs to make use of the VM pointer, and it is not guaranteed that the
  VM will outlive the thread.  SignalSender provides the mechanism by which we
  can nullify the VM pointer when the VM dies so that the thread does not
  continue to use it.

* assembler/ARM64Assembler.h:
(JSC::ARM64Assembler::replaceWithBrk):
* assembler/ARMAssembler.h:
(JSC::ARMAssembler::replaceWithBrk):
* assembler/ARMv7Assembler.h:
(JSC::ARMv7Assembler::replaceWithBkpt):
* assembler/MIPSAssembler.h:
(JSC::MIPSAssembler::replaceWithBkpt):
* assembler/MacroAssemblerARM.h:
(JSC::MacroAssemblerARM::replaceWithJump):
* assembler/MacroAssemblerARM64.h:
(JSC::MacroAssemblerARM64::replaceWithBreakpoint):
* assembler/MacroAssemblerARMv7.h:
(JSC::MacroAssemblerARMv7::replaceWithBreakpoint):
* assembler/MacroAssemblerMIPS.h:
(JSC::MacroAssemblerMIPS::replaceWithJump):
* assembler/MacroAssemblerX86Common.h:
(JSC::MacroAssemblerX86Common::replaceWithBreakpoint):
* assembler/X86Assembler.h:
(JSC::X86Assembler::replaceWithInt3):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::jettison):
(JSC::CodeBlock::hasInstalledVMTrapBreakpoints):
(JSC::CodeBlock::installVMTrapBreakpoints):
* bytecode/CodeBlock.h:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitCheckTraps):
* dfg/DFGCommonData.cpp:
(JSC::DFG::CommonData::installVMTrapBreakpoints):
(JSC::DFG::CommonData::isVMTrapBreakpoint):
* dfg/DFGCommonData.h:
(JSC::DFG::CommonData::hasInstalledVMTrapsBreakpoints):
* dfg/DFGJumpReplacement.cpp:
(JSC::DFG::JumpReplacement::installVMTrapBreakpoint):
* dfg/DFGJumpReplacement.h:
(JSC::DFG::JumpReplacement::dataLocation):
* dfg/DFGNodeType.h:
* heap/CodeBlockSet.cpp:
(JSC::CodeBlockSet::contains):
* heap/CodeBlockSet.h:
* heap/CodeBlockSetInlines.h:
(JSC::CodeBlockSet::iterate):
* heap/Heap.cpp:
(JSC::Heap::forEachCodeBlockIgnoringJITPlansImpl):
* heap/Heap.h:
* heap/HeapInlines.h:
(JSC::Heap::forEachCodeBlockIgnoringJITPlans):
* heap/MachineStackMarker.h:
(JSC::MachineThreads::threadsListHead):
* jit/ExecutableAllocator.cpp:
(JSC::ExecutableAllocator::isValidExecutableMemory):
* jit/ExecutableAllocator.h:
* profiler/ProfilerJettisonReason.cpp:
(WTF::printInternal):
* profiler/ProfilerJettisonReason.h:
* runtime/JSLock.cpp:
(JSC::JSLock::didAcquireLock):
* runtime/Options.cpp:
(JSC::overrideDefaults):
* runtime/Options.h:
* runtime/PlatformThread.h:
(JSC::platformThreadSignal):
* runtime/VM.cpp:
(JSC::VM::~VM):
(JSC::VM::ensureWatchdog):
(JSC::VM::handleTraps): Deleted.
(JSC::VM::setNeedAsynchronousTerminationSupport): Deleted.
* runtime/VM.h:
(JSC::VM::ownerThread):
(JSC::VM::traps):
(JSC::VM::handleTraps):
(JSC::VM::needTrapHandling):
(JSC::VM::needAsynchronousTerminationSupport): Deleted.
* runtime/VMTraps.cpp:
(JSC::VMTraps::vm):
(JSC::SignalContext::SignalContext):
(JSC::SignalContext::adjustPCToPointToTrappingInstruction):
(JSC::vmIsInactive):
(JSC::findActiveVMAndStackBounds):
(JSC::handleSigusr1):
(JSC::handleSigtrap):
(JSC::installSignalHandlers):
(JSC::sanitizedTopCallFrame):
(JSC::isSaneFrame):
(JSC::VMTraps::tryInstallTrapBreakpoints):
(JSC::VMTraps::invalidateCodeBlocksOnStack):
(JSC::VMTraps::VMTraps):
(JSC::VMTraps::willDestroyVM):
(JSC::VMTraps::addSignalSender):
(JSC::VMTraps::removeSignalSender):
(JSC::VMTraps::SignalSender::willDestroyVM):
(JSC::VMTraps::SignalSender::send):
(JSC::VMTraps::fireTrap):
(JSC::VMTraps::handleTraps):
* runtime/VMTraps.h:
(JSC::VMTraps::~VMTraps):
(JSC::VMTraps::needTrapHandling):
(JSC::VMTraps::notifyGrabAllLocks):
(JSC::VMTraps::SignalSender::SignalSender):
(JSC::VMTraps::invalidateCodeBlocksOnStack):
* tools/VMInspector.cpp:
* tools/VMInspector.h:
(JSC::VMInspector::getLock):
(JSC::VMInspector::iterate):

Source/WebCore:

No new tests needed.  This is covered by existing tests.

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

Source/WTF:

Make StackBounds more useful for checking if a pointer is within stack bounds.

* wtf/MetaAllocator.cpp:
(WTF::MetaAllocator::isInAllocatedMemory):
* wtf/MetaAllocator.h:
* wtf/Platform.h:
* wtf/StackBounds.h:
(WTF::StackBounds::emptyBounds):
(WTF::StackBounds::StackBounds):
(WTF::StackBounds::isEmpty):
(WTF::StackBounds::contains):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerARM64Assemblerh">trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerARMAssemblerh">trunk/Source/JavaScriptCore/assembler/ARMAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerARMv7Assemblerh">trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMIPSAssemblerh">trunk/Source/JavaScriptCore/assembler/MIPSAssembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h">trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerMIPSh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh">trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreassemblerX86Assemblerh">trunk/Source/JavaScriptCore/assembler/X86Assembler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockcpp">trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp">trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonDatacpp">trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonDatah">trunk/Source/JavaScriptCore/dfg/DFGCommonData.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJumpReplacementcpp">trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGJumpReplacementh">trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetcpp">trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSeth">trunk/Source/JavaScriptCore/heap/CodeBlockSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapCodeBlockSetInlinesh">trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapcpp">trunk/Source/JavaScriptCore/heap/Heap.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeaph">trunk/Source/JavaScriptCore/heap/Heap.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapHeapInlinesh">trunk/Source/JavaScriptCore/heap/HeapInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreheapMachineStackMarkerh">trunk/Source/JavaScriptCore/heap/MachineStackMarker.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitExecutableAllocatorcpp">trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitExecutableAllocatorh">trunk/Source/JavaScriptCore/jit/ExecutableAllocator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreprofilerProfilerJettisonReasoncpp">trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreprofilerProfilerJettisonReasonh">trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeJSLockcpp">trunk/Source/JavaScriptCore/runtime/JSLock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionscpp">trunk/Source/JavaScriptCore/runtime/Options.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeOptionsh">trunk/Source/JavaScriptCore/runtime/Options.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimePlatformThreadh">trunk/Source/JavaScriptCore/runtime/PlatformThread.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMcpp">trunk/Source/JavaScriptCore/runtime/VM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMh">trunk/Source/JavaScriptCore/runtime/VM.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMTrapscpp">trunk/Source/JavaScriptCore/runtime/VMTraps.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreruntimeVMTrapsh">trunk/Source/JavaScriptCore/runtime/VMTraps.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretoolsVMInspectorcpp">trunk/Source/JavaScriptCore/tools/VMInspector.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoretoolsVMInspectorh">trunk/Source/JavaScriptCore/tools/VMInspector.h</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfMetaAllocatorcpp">trunk/Source/WTF/wtf/MetaAllocator.cpp</a></li>
<li><a href="#trunkSourceWTFwtfMetaAllocatorh">trunk/Source/WTF/wtf/MetaAllocator.h</a></li>
<li><a href="#trunkSourceWTFwtfPlatformh">trunk/Source/WTF/wtf/Platform.h</a></li>
<li><a href="#trunkSourceWTFwtfStackBoundsh">trunk/Source/WTF/wtf/StackBounds.h</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorebindingsjsWorkerScriptControllercpp">trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/ChangeLog        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,3 +1,184 @@
</span><ins>+2017-03-09  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Make the VM Traps mechanism non-polling for the DFG and FTL.
+        https://bugs.webkit.org/show_bug.cgi?id=168920
+        &lt;rdar://problem/30738588&gt;
+
+        Reviewed by Filip Pizlo.
+
+        1. Added a ENABLE(SIGNAL_BASED_VM_TRAPS) configuration in Platform.h.
+           This is currently only enabled for OS(DARWIN) and ENABLE(JIT). 
+        2. Added assembler functions for overwriting an instruction with a breakpoint.
+        3. Added a new JettisonDueToVMTraps jettison reason.
+        4. Added CodeBlock and DFG::CommonData utility functions for over-writing
+           invalidation points with breakpoint instructions.
+        5. The BytecodeGenerator now emits the op_check_traps bytecode unconditionally.
+        6. Remove the JSC_alwaysCheckTraps option because of (4) above.
+           For ports that don't ENABLE(SIGNAL_BASED_VM_TRAPS), we'll force
+           Options::usePollingTraps() to always be true.  This makes the VMTraps
+           implementation fall back to using polling based traps only.
+
+        7. Make VMTraps support signal based traps.
+
+        Some design and implementation details of signal based VM traps:
+
+        - The implementation makes use of 2 signal handlers for SIGUSR1 and SIGTRAP.
+
+        - VMTraps::fireTrap() will set the flag for the requested trap and instantiate
+          a SignalSender.  The SignalSender will send SIGUSR1 to the mutator thread that
+          we want to trap, and check for the occurence of one of the following events:
+
+          a. VMTraps::handleTraps() has been called for the requested trap, or
+
+          b. the VM is inactive and is no longer executing any JS code.  We determine
+             this to be the case if the thread no longer owns the JSLock and the VM's
+             entryScope is null.
+
+             Note: the thread can relinquish the JSLock while the VM's entryScope is not
+             null.  This happens when the thread calls JSLock::dropAllLocks() before
+             calling a host function that may block on IO (or whatever).  For our purpose,
+             this counts as the VM still running JS code, and VM::fireTrap() will still
+             be waiting.
+
+          If the SignalSender does not see either of these events, it will sleep for a
+          while and then re-send SIGUSR1 and check for the events again.  When it sees
+          one of these events, it will consider the mutator to have received the trap
+          request.
+
+        - The SIGUSR1 handler will try to insert breakpoints at the invalidation points
+          in the DFG/FTL codeBlock at the top of the stack.  This allows the mutator
+          thread to break (with a SIGTRAP) exactly at an invalidation point, where it's
+          safe to jettison the codeBlock.
+
+          Note: we cannot have the requester thread (that called VMTraps::fireTrap())
+          insert the breakpoint instructions itself.  This is because we need the
+          register state of the the mutator thread (that we want to trap in) in order to
+          find the codeBlocks that we wish to insert the breakpoints in.  Currently,
+          we don't have a generic way for the requester thread to get the register state
+          of another thread.
+
+        - The SIGTRAP handler will check to see if it is trapping on a breakpoint at an
+          invalidation point.  If so, it will jettison the codeBlock and adjust the PC
+          to re-execute the invalidation OSR exit off-ramp.  After the OSR exit, the
+          baseline JIT code will eventually reach an op_check_traps and call
+          VMTraps::handleTraps().
+
+          If the handler is not trapping at an invalidation point, then it must be
+          observing an assertion failure (which also uses the breakpoint instruction).
+          In this case, the handler will defer to the default SIGTRAP handler and crash.
+
+        - The reason we need the SignalSender is because SignalSender::send() is called
+          from another thread in a loop, so that VMTraps::fireTrap() can return sooner.
+          send() needs to make use of the VM pointer, and it is not guaranteed that the
+          VM will outlive the thread.  SignalSender provides the mechanism by which we
+          can nullify the VM pointer when the VM dies so that the thread does not
+          continue to use it.
+
+        * assembler/ARM64Assembler.h:
+        (JSC::ARM64Assembler::replaceWithBrk):
+        * assembler/ARMAssembler.h:
+        (JSC::ARMAssembler::replaceWithBrk):
+        * assembler/ARMv7Assembler.h:
+        (JSC::ARMv7Assembler::replaceWithBkpt):
+        * assembler/MIPSAssembler.h:
+        (JSC::MIPSAssembler::replaceWithBkpt):
+        * assembler/MacroAssemblerARM.h:
+        (JSC::MacroAssemblerARM::replaceWithJump):
+        * assembler/MacroAssemblerARM64.h:
+        (JSC::MacroAssemblerARM64::replaceWithBreakpoint):
+        * assembler/MacroAssemblerARMv7.h:
+        (JSC::MacroAssemblerARMv7::replaceWithBreakpoint):
+        * assembler/MacroAssemblerMIPS.h:
+        (JSC::MacroAssemblerMIPS::replaceWithJump):
+        * assembler/MacroAssemblerX86Common.h:
+        (JSC::MacroAssemblerX86Common::replaceWithBreakpoint):
+        * assembler/X86Assembler.h:
+        (JSC::X86Assembler::replaceWithInt3):
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::jettison):
+        (JSC::CodeBlock::hasInstalledVMTrapBreakpoints):
+        (JSC::CodeBlock::installVMTrapBreakpoints):
+        * bytecode/CodeBlock.h:
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitCheckTraps):
+        * dfg/DFGCommonData.cpp:
+        (JSC::DFG::CommonData::installVMTrapBreakpoints):
+        (JSC::DFG::CommonData::isVMTrapBreakpoint):
+        * dfg/DFGCommonData.h:
+        (JSC::DFG::CommonData::hasInstalledVMTrapsBreakpoints):
+        * dfg/DFGJumpReplacement.cpp:
+        (JSC::DFG::JumpReplacement::installVMTrapBreakpoint):
+        * dfg/DFGJumpReplacement.h:
+        (JSC::DFG::JumpReplacement::dataLocation):
+        * dfg/DFGNodeType.h:
+        * heap/CodeBlockSet.cpp:
+        (JSC::CodeBlockSet::contains):
+        * heap/CodeBlockSet.h:
+        * heap/CodeBlockSetInlines.h:
+        (JSC::CodeBlockSet::iterate):
+        * heap/Heap.cpp:
+        (JSC::Heap::forEachCodeBlockIgnoringJITPlansImpl):
+        * heap/Heap.h:
+        * heap/HeapInlines.h:
+        (JSC::Heap::forEachCodeBlockIgnoringJITPlans):
+        * heap/MachineStackMarker.h:
+        (JSC::MachineThreads::threadsListHead):
+        * jit/ExecutableAllocator.cpp:
+        (JSC::ExecutableAllocator::isValidExecutableMemory):
+        * jit/ExecutableAllocator.h:
+        * profiler/ProfilerJettisonReason.cpp:
+        (WTF::printInternal):
+        * profiler/ProfilerJettisonReason.h:
+        * runtime/JSLock.cpp:
+        (JSC::JSLock::didAcquireLock):
+        * runtime/Options.cpp:
+        (JSC::overrideDefaults):
+        * runtime/Options.h:
+        * runtime/PlatformThread.h:
+        (JSC::platformThreadSignal):
+        * runtime/VM.cpp:
+        (JSC::VM::~VM):
+        (JSC::VM::ensureWatchdog):
+        (JSC::VM::handleTraps): Deleted.
+        (JSC::VM::setNeedAsynchronousTerminationSupport): Deleted.
+        * runtime/VM.h:
+        (JSC::VM::ownerThread):
+        (JSC::VM::traps):
+        (JSC::VM::handleTraps):
+        (JSC::VM::needTrapHandling):
+        (JSC::VM::needAsynchronousTerminationSupport): Deleted.
+        * runtime/VMTraps.cpp:
+        (JSC::VMTraps::vm):
+        (JSC::SignalContext::SignalContext):
+        (JSC::SignalContext::adjustPCToPointToTrappingInstruction):
+        (JSC::vmIsInactive):
+        (JSC::findActiveVMAndStackBounds):
+        (JSC::handleSigusr1):
+        (JSC::handleSigtrap):
+        (JSC::installSignalHandlers):
+        (JSC::sanitizedTopCallFrame):
+        (JSC::isSaneFrame):
+        (JSC::VMTraps::tryInstallTrapBreakpoints):
+        (JSC::VMTraps::invalidateCodeBlocksOnStack):
+        (JSC::VMTraps::VMTraps):
+        (JSC::VMTraps::willDestroyVM):
+        (JSC::VMTraps::addSignalSender):
+        (JSC::VMTraps::removeSignalSender):
+        (JSC::VMTraps::SignalSender::willDestroyVM):
+        (JSC::VMTraps::SignalSender::send):
+        (JSC::VMTraps::fireTrap):
+        (JSC::VMTraps::handleTraps):
+        * runtime/VMTraps.h:
+        (JSC::VMTraps::~VMTraps):
+        (JSC::VMTraps::needTrapHandling):
+        (JSC::VMTraps::notifyGrabAllLocks):
+        (JSC::VMTraps::SignalSender::SignalSender):
+        (JSC::VMTraps::invalidateCodeBlocksOnStack):
+        * tools/VMInspector.cpp:
+        * tools/VMInspector.h:
+        (JSC::VMInspector::getLock):
+        (JSC::VMInspector::iterate):
+
</ins><span class="cx"> 2017-03-09  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebKit: JSC: JSObject::ensureLength doesn't check if ensureLengthSlow failed
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerARM64Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/ARM64Assembler.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2536,6 +2536,13 @@
</span><span class="cx">         linkPointer(addressOf(code, where), valuePtr);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithBrk(void* where)
+    {
+        int insn = excepnGeneration(ExcepnOp_BREAKPOINT, 0, 0);
+        performJITMemcpy(where, &amp;insn, sizeof(int));
+        cacheFlush(where, sizeof(int));
+    }
+
</ins><span class="cx">     static void replaceWithJump(void* where, void* to)
</span><span class="cx">     {
</span><span class="cx">         intptr_t offset = (reinterpret_cast&lt;intptr_t&gt;(to) - reinterpret_cast&lt;intptr_t&gt;(where)) &gt;&gt; 2;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerARMAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/ARMAssembler.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/ARMAssembler.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/ARMAssembler.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -995,6 +995,13 @@
</span><span class="cx">             return reinterpret_cast&lt;void*&gt;(readPointer(reinterpret_cast&lt;void*&gt;(getAbsoluteJumpAddress(from))));
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        static void replaceWithBrk(void* instructionStart)
+        {
+            ARMWord* instruction = reinterpret_cast&lt;ARMWord*&gt;(instructionStart);
+            instruction[0] = BKPT;
+            cacheFlush(instruction, sizeof(ARMWord));
+        }
+
</ins><span class="cx">         static void replaceWithJump(void* instructionStart, void* to)
</span><span class="cx">         {
</span><span class="cx">             ARMWord* instruction = reinterpret_cast&lt;ARMWord*&gt;(instructionStart);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerARMv7Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/ARMv7Assembler.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2327,7 +2327,17 @@
</span><span class="cx">     {
</span><span class="cx">         return reinterpret_cast&lt;void*&gt;(readInt32(where));
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    static void replaceWithBkpt(void* instructionStart)
+    {
+        ASSERT(!(bitwise_cast&lt;uintptr_t&gt;(instructionStart) &amp; 1));
+
+        uint16_t* ptr = reinterpret_cast&lt;uint16_t*&gt;(instructionStart);
+        uint16_t instructions = OP_BKPT;
+        performJITMemcpy(ptr, &amp;instructions, sizeof(uint16_t));
+        cacheFlush(ptr, sizeof(uint16_t));
+    }
+
</ins><span class="cx">     static void replaceWithJump(void* instructionStart, void* to)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!(bitwise_cast&lt;uintptr_t&gt;(instructionStart) &amp; 1));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMIPSAssemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MIPSAssembler.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MIPSAssembler.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MIPSAssembler.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -915,6 +915,15 @@
</span><span class="cx">         cacheFlush(insn, codeSize);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithBkpt(void* instructionStart)
+    {
+        ASSERT(!(bitwise_cast&lt;uintptr_t&gt;(instructionStart) &amp; 3));
+        MIPSWord* insn = reinterpret_cast&lt;MIPSWord*&gt;(reinterpret_cast&lt;intptr_t&gt;(code));
+        int value = 512; /* BRK_BUG */
+        insn[0] = (0x0000000d | ((value &amp; 0x3ff) &lt;&lt; OP_SH_CODE));
+        cacheFlush(instructionStart, sizeof(MIPSWord));
+    }
+
</ins><span class="cx">     static void replaceWithJump(void* instructionStart, void* to)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(!(bitwise_cast&lt;uintptr_t&gt;(instructionStart) &amp; 3));
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1482,6 +1482,11 @@
</span><span class="cx">         return FunctionPtr(reinterpret_cast&lt;void(*)()&gt;(ARMAssembler::readCallTarget(call.dataLocation())));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithJump(CodeLocationLabel instructionStart)
+    {
+        ARMAssembler::replaceWithBkpt(instructionStart.executableAddress());
+    }
+
</ins><span class="cx">     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
</span><span class="cx">     {
</span><span class="cx">         ARMAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARM64h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARM64.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -3406,6 +3406,11 @@
</span><span class="cx">         return FunctionPtr(reinterpret_cast&lt;void(*)()&gt;(ARM64Assembler::readCallTarget(call.dataLocation())));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithBreakpoint(CodeLocationLabel instructionStart)
+    {
+        ARM64Assembler::replaceWithBrk(instructionStart.executableAddress());
+    }
+
</ins><span class="cx">     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
</span><span class="cx">     {
</span><span class="cx">         ARM64Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerARMv7h"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1349,6 +1349,11 @@
</span><span class="cx">         m_assembler.dmbISHST();
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    static void replaceWithBreakpoint(CodeLocationLabel instructionStart)
+    {
+        ARMv7Assembler::replaceWithBkpt(instructionStart.dataLocation());
+    }
+
</ins><span class="cx">     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
</span><span class="cx">     {
</span><span class="cx">         ARMv7Assembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerMIPSh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2978,6 +2978,11 @@
</span><span class="cx">         return FunctionPtr(reinterpret_cast&lt;void(*)()&gt;(MIPSAssembler::readCallTarget(call.dataLocation())));
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithJump(CodeLocationLabel instructionStart)
+    {
+        MIPSAssembler::replaceWithBkpt(instructionStart.executableAddress());
+    }
+
</ins><span class="cx">     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
</span><span class="cx">     {
</span><span class="cx">         MIPSAssembler::replaceWithJump(instructionStart.dataLocation(), destination.dataLocation());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerMacroAssemblerX86Commonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2756,6 +2756,11 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithBreakpoint(CodeLocationLabel instructionStart)
+    {
+        X86Assembler::replaceWithInt3(instructionStart.executableAddress());
+    }
+
</ins><span class="cx">     static void replaceWithJump(CodeLocationLabel instructionStart, CodeLocationLabel destination)
</span><span class="cx">     {
</span><span class="cx">         X86Assembler::replaceWithJump(instructionStart.executableAddress(), destination.executableAddress());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreassemblerX86Assemblerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/assembler/X86Assembler.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/assembler/X86Assembler.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2902,6 +2902,12 @@
</span><span class="cx">         return reinterpret_cast&lt;void**&gt;(where)[-1];
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static void replaceWithInt3(void* instructionStart)
+    {
+        uint8_t* ptr = reinterpret_cast&lt;uint8_t*&gt;(instructionStart);
+        ptr[0] = static_cast&lt;uint8_t&gt;(OP_INT3);
+    }
+
</ins><span class="cx">     static void replaceWithJump(void* instructionStart, void* to)
</span><span class="cx">     {
</span><span class="cx">         uint8_t* ptr = reinterpret_cast&lt;uint8_t*&gt;(instructionStart);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008-2010, 2012-2017 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2008 Cameron Zwarich &lt;cwzwarich@uwaterloo.ca&gt;
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -1904,7 +1904,7 @@
</span><span class="cx">     if (alternative())
</span><span class="cx">         alternative()-&gt;optimizeAfterWarmUp();
</span><span class="cx"> 
</span><del>-    if (reason != Profiler::JettisonDueToOldAge)
</del><ins>+    if (reason != Profiler::JettisonDueToOldAge &amp;&amp; reason != Profiler::JettisonDueToVMTraps)
</ins><span class="cx">         tallyFrequentExitSites();
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span><span class="cx"> 
</span><span class="lines">@@ -2966,6 +2966,36 @@
</span><span class="cx">     m_llintExecuteCounter.setNewThreshold(thresholdForJIT(Options::thresholdForJITSoon()), this);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool CodeBlock::hasInstalledVMTrapBreakpoints() const
+{
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    
+    // This function may be called from a signal handler. We need to be
+    // careful to not call anything that is not signal handler safe, e.g.
+    // we should not perturb the refCount of m_jitCode.
+    if (!JITCode::isOptimizingJIT(jitType()))
+        return false;
+    return m_jitCode-&gt;dfgCommon()-&gt;hasInstalledVMTrapsBreakpoints();
+#else
+    return false;
+#endif
+}
+
+bool CodeBlock::installVMTrapBreakpoints()
+{
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    // This function may be called from a signal handler. We need to be
+    // careful to not call anything that is not signal handler safe, e.g.
+    // we should not perturb the refCount of m_jitCode.
+    if (!JITCode::isOptimizingJIT(jitType()))
+        return false;
+    m_jitCode-&gt;dfgCommon()-&gt;installVMTrapBreakpoints();
+    return true;
+#else
+    return false;
+#endif
+}
+
</ins><span class="cx"> void CodeBlock::dumpMathICStats()
</span><span class="cx"> {
</span><span class="cx"> #if ENABLE(MATH_IC_STATS)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008-2016 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2008-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2008 Cameron Zwarich &lt;cwzwarich@uwaterloo.ca&gt;
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -203,6 +203,9 @@
</span><span class="cx">     bool isStrictMode() const { return m_isStrictMode; }
</span><span class="cx">     ECMAMode ecmaMode() const { return isStrictMode() ? StrictMode : NotStrictMode; }
</span><span class="cx"> 
</span><ins>+    bool hasInstalledVMTrapBreakpoints() const;
+    bool installVMTrapBreakpoints();
+
</ins><span class="cx">     inline bool isKnownNotImmediate(int index)
</span><span class="cx">     {
</span><span class="cx">         if (index == m_thisRegister.offset() &amp;&amp; !m_isStrictMode)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecompilerBytecodeGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1274,8 +1274,7 @@
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::emitCheckTraps()
</span><span class="cx"> {
</span><del>-    if (Options::alwaysCheckTraps() || vm()-&gt;watchdog() || vm()-&gt;needAsynchronousTerminationSupport())
-        emitOpcode(op_check_traps);
</del><ins>+    emitOpcode(op_check_traps);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void BytecodeGenerator::retrieveLastBinaryOp(int&amp; dstIndex, int&amp; src1Index, int&amp; src2Index)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonDatacpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommonData.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -97,6 +97,26 @@
</span><span class="cx">     return true;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CommonData::installVMTrapBreakpoints()
+{
+    if (!isStillValid || hasVMTrapsBreakpointsInstalled)
+        return;
+    hasVMTrapsBreakpointsInstalled = true;
+    for (unsigned i = jumpReplacements.size(); i--;)
+        jumpReplacements[i].installVMTrapBreakpoint();
+}
+
+bool CommonData::isVMTrapBreakpoint(void* address)
+{
+    if (!isStillValid)
+        return false;
+    for (unsigned i = jumpReplacements.size(); i--;) {
+        if (address == jumpReplacements[i].dataLocation())
+            return true;
+    }
+    return false;
+}
+
</ins><span class="cx"> void CommonData::validateReferences(const TrackedReferences&amp; trackedReferences)
</span><span class="cx"> {
</span><span class="cx">     if (InlineCallFrameSet* set = inlineCallFrames.get()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommonData.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommonData.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommonData.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -86,7 +86,10 @@
</span><span class="cx">     void shrinkToFit();
</span><span class="cx">     
</span><span class="cx">     bool invalidate(); // Returns true if we did invalidate, or false if the code block was already invalidated.
</span><del>-    
</del><ins>+    bool hasInstalledVMTrapsBreakpoints() const { return isStillValid &amp;&amp; hasVMTrapsBreakpointsInstalled; }
+    void installVMTrapBreakpoints();
+    bool isVMTrapBreakpoint(void* address);
+
</ins><span class="cx">     unsigned requiredRegisterCountForExecutionAndExit() const
</span><span class="cx">     {
</span><span class="cx">         return std::max(frameRegisterCount, requiredRegisterCountForExit);
</span><span class="lines">@@ -112,6 +115,7 @@
</span><span class="cx">     bool livenessHasBeenProved; // Initialized and used on every GC.
</span><span class="cx">     bool allTransitionsHaveBeenMarked; // Initialized and used on every GC.
</span><span class="cx">     bool isStillValid;
</span><ins>+    bool hasVMTrapsBreakpointsInstalled { false };
</ins><span class="cx">     
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx">     std::unique_ptr&lt;Bag&lt;double&gt;&gt; doubleConstants;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJumpReplacementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -41,6 +41,11 @@
</span><span class="cx">     MacroAssembler::replaceWithJump(m_source, m_destination);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void JumpReplacement::installVMTrapBreakpoint()
+{
+    MacroAssembler::replaceWithBreakpoint(m_source);
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGJumpReplacementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/dfg/DFGJumpReplacement.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void fire();
</span><ins>+    void installVMTrapBreakpoint();
+    void* dataLocation() const { return m_source.dataLocation(); }
</ins><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     CodeLocationLabel m_source;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -391,7 +391,7 @@
</span><span class="cx">     /* flow. */\
</span><span class="cx">     macro(BottomValue, NodeResultJS) \
</span><span class="cx">     \
</span><del>-    /* Checks for VM traps. If there is a trap, we call operation operationHandleTraps */ \
</del><ins>+    /* Checks for VM traps. If there is a trap, we'll jettison or call operation operationHandleTraps. */ \
</ins><span class="cx">     macro(CheckTraps, NodeMustGenerate) \
</span><span class="cx">     /* Write barriers */\
</span><span class="cx">     macro(StoreBarrier, NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -103,7 +103,7 @@
</span><span class="cx">     promoteYoungCodeBlocks(locker);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool CodeBlockSet::contains(const LockHolder&amp;, void* candidateCodeBlock)
</del><ins>+bool CodeBlockSet::contains(const AbstractLocker&amp;, void* candidateCodeBlock)
</ins><span class="cx"> {
</span><span class="cx">     RELEASE_ASSERT(m_lock.isLocked());
</span><span class="cx">     CodeBlock* codeBlock = static_cast&lt;CodeBlock*&gt;(candidateCodeBlock);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSet.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSet.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -72,7 +72,7 @@
</span><span class="cx">     
</span><span class="cx">     void clearCurrentlyExecuting();
</span><span class="cx"> 
</span><del>-    bool contains(const LockHolder&amp;, void* candidateCodeBlock);
</del><ins>+    bool contains(const AbstractLocker&amp;, void* candidateCodeBlock);
</ins><span class="cx">     Lock&amp; getLock() { return m_lock; }
</span><span class="cx"> 
</span><span class="cx">     // Visits each CodeBlock in the heap until the visitor function returns true
</span><span class="lines">@@ -79,6 +79,7 @@
</span><span class="cx">     // to indicate that it is done iterating, or until every CodeBlock has been
</span><span class="cx">     // visited.
</span><span class="cx">     template&lt;typename Functor&gt; void iterate(const Functor&amp;);
</span><ins>+    template&lt;typename Functor&gt; void iterate(const AbstractLocker&amp;, const Functor&amp;);
</ins><span class="cx">     
</span><span class="cx">     template&lt;typename Functor&gt; void iterateCurrentlyExecuting(const Functor&amp;);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapCodeBlockSetInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/CodeBlockSetInlines.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -63,7 +63,13 @@
</span><span class="cx"> template&lt;typename Functor&gt;
</span><span class="cx"> void CodeBlockSet::iterate(const Functor&amp; functor)
</span><span class="cx"> {
</span><del>-    LockHolder locker(m_lock);
</del><ins>+    auto locker = holdLock(m_lock);
+    iterate(locker, functor);
+}
+
+template&lt;typename Functor&gt;
+void CodeBlockSet::iterate(const AbstractLocker&amp;, const Functor&amp; functor)
+{
</ins><span class="cx">     for (auto&amp; codeBlock : m_oldCodeBlocks) {
</span><span class="cx">         bool done = functor(codeBlock);
</span><span class="cx">         if (done)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/Heap.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -2330,9 +2330,9 @@
</span><span class="cx">     return m_codeBlocks-&gt;iterate(func);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void Heap::forEachCodeBlockIgnoringJITPlansImpl(const ScopedLambda&lt;bool(CodeBlock*)&gt;&amp; func)
</del><ins>+void Heap::forEachCodeBlockIgnoringJITPlansImpl(const AbstractLocker&amp; locker, const ScopedLambda&lt;bool(CodeBlock*)&gt;&amp; func)
</ins><span class="cx"> {
</span><del>-    return m_codeBlocks-&gt;iterate(func);
</del><ins>+    return m_codeBlocks-&gt;iterate(locker, func);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void Heap::writeBarrierSlowPath(const JSCell* from)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeaph"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/Heap.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/Heap.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/Heap.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -226,7 +226,7 @@
</span><span class="cx">     
</span><span class="cx">     template&lt;typename Functor&gt; void forEachProtectedCell(const Functor&amp;);
</span><span class="cx">     template&lt;typename Functor&gt; void forEachCodeBlock(const Functor&amp;);
</span><del>-    template&lt;typename Functor&gt; void forEachCodeBlockIgnoringJITPlans(const Functor&amp;);
</del><ins>+    template&lt;typename Functor&gt; void forEachCodeBlockIgnoringJITPlans(const AbstractLocker&amp; codeBlockSetLocker, const Functor&amp;);
</ins><span class="cx"> 
</span><span class="cx">     HandleSet* handleSet() { return &amp;m_handleSet; }
</span><span class="cx">     HandleStack* handleStack() { return &amp;m_handleStack; }
</span><span class="lines">@@ -499,7 +499,7 @@
</span><span class="cx">     size_t bytesVisited();
</span><span class="cx">     
</span><span class="cx">     void forEachCodeBlockImpl(const ScopedLambda&lt;bool(CodeBlock*)&gt;&amp;);
</span><del>-    void forEachCodeBlockIgnoringJITPlansImpl(const ScopedLambda&lt;bool(CodeBlock*)&gt;&amp;);
</del><ins>+    void forEachCodeBlockIgnoringJITPlansImpl(const AbstractLocker&amp; codeBlockSetLocker, const ScopedLambda&lt;bool(CodeBlock*)&gt;&amp;);
</ins><span class="cx">     
</span><span class="cx">     void setMutatorShouldBeFenced(bool value);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapHeapInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/HeapInlines.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/HeapInlines.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/HeapInlines.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -155,9 +155,9 @@
</span><span class="cx">     forEachCodeBlockImpl(scopedLambdaRef&lt;bool(CodeBlock*)&gt;(func));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-template&lt;typename Functor&gt; inline void Heap::forEachCodeBlockIgnoringJITPlans(const Functor&amp; func)
</del><ins>+template&lt;typename Functor&gt; inline void Heap::forEachCodeBlockIgnoringJITPlans(const AbstractLocker&amp; codeBlockSetLocker, const Functor&amp; func)
</ins><span class="cx"> {
</span><del>-    forEachCodeBlockIgnoringJITPlansImpl(scopedLambdaRef&lt;bool(CodeBlock*)&gt;(func));
</del><ins>+    forEachCodeBlockIgnoringJITPlansImpl(codeBlockSetLocker, scopedLambdaRef&lt;bool(CodeBlock*)&gt;(func));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename Functor&gt; inline void Heap::forEachProtectedCell(const Functor&amp; functor)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreheapMachineStackMarkerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/heap/MachineStackMarker.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/heap/MachineStackMarker.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/heap/MachineStackMarker.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -135,7 +135,7 @@
</span><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     Lock&amp; getLock() { return m_registeredThreadsMutex; }
</span><del>-    Thread* threadsListHead(const LockHolder&amp;) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
</del><ins>+    Thread* threadsListHead(const AbstractLocker&amp;) const { ASSERT(m_registeredThreadsMutex.isLocked()); return m_registeredThreads; }
</ins><span class="cx">     Thread* machineThreadForCurrentThread();
</span><span class="cx"> 
</span><span class="cx"> private:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitExecutableAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/jit/ExecutableAllocator.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -399,7 +399,7 @@
</span><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool ExecutableAllocator::isValidExecutableMemory(const LockHolder&amp; locker, void* address)
</del><ins>+bool ExecutableAllocator::isValidExecutableMemory(const AbstractLocker&amp; locker, void* address)
</ins><span class="cx"> {
</span><span class="cx">     return allocator-&gt;isInAllocatedMemory(locker, address);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitExecutableAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ExecutableAllocator.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ExecutableAllocator.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/jit/ExecutableAllocator.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -136,7 +136,7 @@
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;ExecutableMemoryHandle&gt; allocate(VM&amp;, size_t sizeInBytes, void* ownerUID, JITCompilationEffort);
</span><span class="cx"> 
</span><del>-    bool isValidExecutableMemory(const LockHolder&amp;, void* address);
</del><ins>+    bool isValidExecutableMemory(const AbstractLocker&amp;, void* address);
</ins><span class="cx"> 
</span><span class="cx">     static size_t committedByteCount();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreprofilerProfilerJettisonReasoncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -65,6 +65,9 @@
</span><span class="cx">     case JettisonDueToOldAge:
</span><span class="cx">         out.print(&quot;JettisonDueToOldAge&quot;);
</span><span class="cx">         return;
</span><ins>+    case JettisonDueToVMTraps:
+        out.print(&quot;JettisonDueToVMTraps&quot;);
+        return;
</ins><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreprofilerProfilerJettisonReasonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -37,7 +37,8 @@
</span><span class="cx">     JettisonDueToOSRExit,
</span><span class="cx">     JettisonDueToProfiledWatchpoint,
</span><span class="cx">     JettisonDueToUnprofiledWatchpoint,
</span><del>-    JettisonDueToOldAge
</del><ins>+    JettisonDueToOldAge,
+    JettisonDueToVMTraps
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } } // namespace JSC::Profiler
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeJSLockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/JSLock.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/JSLock.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/JSLock.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -144,6 +144,8 @@
</span><span class="cx"> 
</span><span class="cx">     m_vm-&gt;heap.machineThreads().addCurrentThread();
</span><span class="cx"> 
</span><ins>+    m_vm-&gt;traps().notifyGrabAllLocks();
+
</ins><span class="cx"> #if ENABLE(SAMPLING_PROFILER)
</span><span class="cx">     // Note: this must come after addCurrentThread().
</span><span class="cx">     if (SamplingProfiler* samplingProfiler = m_vm-&gt;samplingProfiler())
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/Options.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -332,6 +332,10 @@
</span><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx">     Options::useSigillCrashAnalyzer() = true;
</span><span class="cx"> #endif
</span><ins>+
+#if !ENABLE(SIGNAL_BASED_VM_TRAPS)
+    Options::usePollingTraps() = true;
+#endif
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static void recomputeDependentOptions()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeOptionsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/Options.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/Options.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/Options.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -406,7 +406,6 @@
</span><span class="cx">     v(bool, useSigillCrashAnalyzer, false, Configurable, &quot;logs data about SIGILL crashes&quot;) \
</span><span class="cx">     \
</span><span class="cx">     v(unsigned, watchdog, 0, Normal, &quot;watchdog timeout (0 = Disabled, N = a timeout period of N milliseconds)&quot;) \
</span><del>-    v(bool, alwaysCheckTraps, false, Normal, &quot;always emit op_check_traps bytecode&quot;) \
</del><span class="cx">     v(bool, usePollingTraps, false, Normal, &quot;use polling (instead of signalling) VM traps&quot;) \
</span><span class="cx">     \
</span><span class="cx">     v(bool, useICStats, false, Normal, nullptr) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimePlatformThreadh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/PlatformThread.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/PlatformThread.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/PlatformThread.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -56,4 +56,13 @@
</span><span class="cx"> #endif
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#if OS(DARWIN)
+inline bool platformThreadSignal(PlatformThread platformThread, int signalNumber)
+{
+    pthread_t pthreadID = pthread_from_mach_thread_np(platformThread);
+    int errNo = pthread_kill(pthreadID, signalNumber);
+    return !errNo; // A 0 errNo means success.
+}
+#endif
+
</ins><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/VM.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -98,7 +98,6 @@
</span><span class="cx"> #include &quot;StrictEvalActivation.h&quot;
</span><span class="cx"> #include &quot;StrongInlines.h&quot;
</span><span class="cx"> #include &quot;StructureInlines.h&quot;
</span><del>-#include &quot;ThrowScope.h&quot;
</del><span class="cx"> #include &quot;TypeProfiler.h&quot;
</span><span class="cx"> #include &quot;TypeProfilerLog.h&quot;
</span><span class="cx"> #include &quot;UnlinkedCodeBlock.h&quot;
</span><span class="lines">@@ -360,6 +359,7 @@
</span><span class="cx"> {
</span><span class="cx">     if (UNLIKELY(m_watchdog))
</span><span class="cx">         m_watchdog-&gt;willDestroyVM(this);
</span><ins>+    m_traps.willDestroyVM();
</ins><span class="cx">     VMInspector::instance().remove(this);
</span><span class="cx"> 
</span><span class="cx">     // Never GC, ever again.
</span><span class="lines">@@ -462,21 +462,8 @@
</span><span class="cx"> 
</span><span class="cx"> Watchdog&amp; VM::ensureWatchdog()
</span><span class="cx"> {
</span><del>-    if (!m_watchdog) {
-        Options::usePollingTraps() = true; // Force polling traps on until we have support for signal based traps.
-
</del><ins>+    if (!m_watchdog)
</ins><span class="cx">         m_watchdog = adoptRef(new Watchdog(this));
</span><del>-        
-        // 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
-        // same as a plain C++ pointer, and loads the address of Watchdog from it.
-        RELEASE_ASSERT(*reinterpret_cast&lt;Watchdog**&gt;(&amp;m_watchdog) == m_watchdog.get());
-
-        // And if we've previously compiled any functions, we need to revert
-        // them because they don't have the needed polling checks for the watchdog
-        // yet.
-        deleteAllCode(PreventCollectionAndDeleteAllCode);
-    }
</del><span class="cx">     return *m_watchdog;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -949,39 +936,4 @@
</span><span class="cx"> }
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-void VM::handleTraps(ExecState* exec, VMTraps::Mask mask)
-{
-    auto scope = DECLARE_THROW_SCOPE(*this);
-
-    ASSERT(needTrapHandling(mask));
-    while (needTrapHandling(mask)) {
-        auto trapEventType = m_traps.takeTopPriorityTrap(mask);
-        switch (trapEventType) {
-        case VMTraps::NeedDebuggerBreak:
-            if (Options::alwaysCheckTraps())
-                dataLog(&quot;VM &quot;, RawPointer(this), &quot; on pid &quot;, getCurrentProcessID(), &quot; received NeedDebuggerBreak trap\n&quot;);
-            return;
-
-        case VMTraps::NeedWatchdogCheck:
-            ASSERT(m_watchdog);
-            if (LIKELY(!m_watchdog-&gt;shouldTerminate(exec)))
-                continue;
-            FALLTHROUGH;
-
-        case VMTraps::NeedTermination:
-            JSC::throwException(exec, scope, createTerminatedExecutionException(this));
-            return;
-
-        default:
-            RELEASE_ASSERT_NOT_REACHED();
-        }
-    }
-}
-
-void VM::setNeedAsynchronousTerminationSupport()
-{
-    Options::usePollingTraps() = true; // Force polling traps on until we have support for signal based traps.
-    m_needAsynchronousTerminationSupport = true;
-}
-
</del><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VM.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VM.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/VM.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -269,7 +269,7 @@
</span><span class="cx">     static Ref&lt;VM&gt; createContextGroup(HeapType = SmallHeap);
</span><span class="cx">     JS_EXPORT_PRIVATE ~VM();
</span><span class="cx"> 
</span><del>-    JS_EXPORT_PRIVATE Watchdog&amp; ensureWatchdog();
</del><ins>+    Watchdog&amp; ensureWatchdog();
</ins><span class="cx">     Watchdog* watchdog() { return m_watchdog.get(); }
</span><span class="cx"> 
</span><span class="cx">     HeapProfiler* heapProfiler() const { return m_heapProfiler.get(); }
</span><span class="lines">@@ -314,7 +314,7 @@
</span><span class="cx">     // topVMEntryFrame.
</span><span class="cx">     // FIXME: This should be a void*, because it might not point to a CallFrame.
</span><span class="cx">     // https://bugs.webkit.org/show_bug.cgi?id=160441
</span><del>-    ExecState* topCallFrame;
</del><ins>+    ExecState* topCallFrame { nullptr };
</ins><span class="cx">     JSWebAssemblyInstance* topJSWebAssemblyInstance;
</span><span class="cx">     Strong&lt;Structure&gt; structureStructure;
</span><span class="cx">     Strong&lt;Structure&gt; structureRareDataStructure;
</span><span class="lines">@@ -672,9 +672,14 @@
</span><span class="cx">     template&lt;typename Func&gt;
</span><span class="cx">     void logEvent(CodeBlock*, const char* summary, const Func&amp; func);
</span><span class="cx"> 
</span><del>-    void handleTraps(ExecState*, VMTraps::Mask = VMTraps::Mask::allEventTypes());
</del><ins>+    std::optional&lt;PlatformThread&gt; ownerThread() const { return m_apiLock-&gt;ownerThread(); }
</ins><span class="cx"> 
</span><del>-    bool needTrapHandling(VMTraps::Mask mask = VMTraps::Mask::allEventTypes()) { return m_traps.needTrapHandling(mask); }
</del><ins>+    VMTraps&amp; traps() { return m_traps; }
+
+    void handleTraps(ExecState* exec, VMTraps::Mask mask = VMTraps::Mask::allEventTypes()) { m_traps.handleTraps(exec, mask); }
+
+    bool needTrapHandling() { return m_traps.needTrapHandling(); }
+    bool needTrapHandling(VMTraps::Mask mask) { return m_traps.needTrapHandling(mask); }
</ins><span class="cx">     void* needTrapHandlingAddress() { return m_traps.needTrapHandlingAddress(); }
</span><span class="cx"> 
</span><span class="cx">     void notifyNeedDebuggerBreak() { m_traps.fireTrap(VMTraps::NeedDebuggerBreak); }
</span><span class="lines">@@ -681,9 +686,6 @@
</span><span class="cx">     void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
</span><span class="cx">     void notifyNeedWatchdogCheck() { m_traps.fireTrap(VMTraps::NeedWatchdogCheck); }
</span><span class="cx"> 
</span><del>-    bool needAsynchronousTerminationSupport() const { return m_needAsynchronousTerminationSupport; }
-    JS_EXPORT_PRIVATE void setNeedAsynchronousTerminationSupport();
-
</del><span class="cx"> private:
</span><span class="cx">     friend class LLIntOffsetsExtractor;
</span><span class="cx"> 
</span><span class="lines">@@ -725,8 +727,6 @@
</span><span class="cx">     bool isSafeToRecurseSoftCLoop() const;
</span><span class="cx"> #endif // !ENABLE(JIT)
</span><span class="cx"> 
</span><del>-    std::optional&lt;PlatformThread&gt; ownerThread() const { return m_apiLock-&gt;ownerThread(); }
-
</del><span class="cx">     JS_EXPORT_PRIVATE void throwException(ExecState*, Exception*);
</span><span class="cx">     JS_EXPORT_PRIVATE JSValue throwException(ExecState*, JSValue);
</span><span class="cx">     JS_EXPORT_PRIVATE JSObject* throwException(ExecState*, JSObject*);
</span><span class="lines">@@ -770,7 +770,6 @@
</span><span class="cx">     DeletePropertyMode m_deletePropertyMode { DeletePropertyMode::Default };
</span><span class="cx">     bool m_globalConstRedeclarationShouldThrow { true };
</span><span class="cx">     bool m_shouldBuildPCToCodeOriginMapping { false };
</span><del>-    bool m_needAsynchronousTerminationSupport { false };
</del><span class="cx">     std::unique_ptr&lt;CodeCache&gt; m_codeCache;
</span><span class="cx">     std::unique_ptr&lt;BuiltinExecutables&gt; m_builtinExecutables;
</span><span class="cx">     HashMap&lt;String, RefPtr&lt;WatchpointSet&gt;&gt; m_impurePropertyWatchpointSets;
</span><span class="lines">@@ -799,6 +798,7 @@
</span><span class="cx">     friend class CatchScope;
</span><span class="cx">     friend class ExceptionScope;
</span><span class="cx">     friend class ThrowScope;
</span><ins>+    friend class VMTraps;
</ins><span class="cx">     friend class WTF::DoublyLinkedListNode&lt;VM&gt;;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMTrapscpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VMTraps.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VMTraps.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/VMTraps.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -26,14 +26,552 @@
</span><span class="cx"> #include &quot;config.h&quot;
</span><span class="cx"> #include &quot;VMTraps.h&quot;
</span><span class="cx"> 
</span><ins>+#include &quot;CallFrame.h&quot;
+#include &quot;CodeBlock.h&quot;
+#include &quot;CodeBlockSet.h&quot;
+#include &quot;DFGCommonData.h&quot;
+#include &quot;ExceptionHelpers.h&quot;
+#include &quot;HeapInlines.h&quot;
+#include &quot;LLIntPCRanges.h&quot;
+#include &quot;MachineStackMarker.h&quot;
+#include &quot;MacroAssembler.h&quot;
+#include &quot;VM.h&quot;
+#include &quot;VMInspector.h&quot;
+#include &quot;Watchdog.h&quot;
+#include &lt;wtf/ProcessID.h&gt;
+
+#if OS(DARWIN)
+#include &lt;signal.h&gt;
+#endif
+
</ins><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><del>-void VMTraps::fireTrap(VMTraps::EventType eventType)
</del><ins>+ALWAYS_INLINE VM&amp; VMTraps::vm() const
</ins><span class="cx"> {
</span><ins>+    return *bitwise_cast&lt;VM*&gt;(bitwise_cast&lt;uintptr_t&gt;(this) - OBJECT_OFFSETOF(VM, m_traps));
+}
+
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+
+struct sigaction originalSigusr1Action;
+struct sigaction originalSigtrapAction;
+
+#if CPU(X86_64)
+
+struct SignalContext {
+    SignalContext(mcontext_t&amp; mcontext)
+        : mcontext(mcontext)
+        , trapPC(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__rip))
+        , stackPointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__rsp))
+        , framePointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__rbp))
+    {
+        // On X86_64, SIGTRAP reports the address after the trapping PC. So, dec by 1.
+        trapPC = reinterpret_cast&lt;uint8_t*&gt;(trapPC) - 1;
+    }
+
+    void adjustPCToPointToTrappingInstruction()
+    {
+        mcontext-&gt;__ss.__rip = reinterpret_cast&lt;uintptr_t&gt;(trapPC);
+    }
+
+    mcontext_t&amp; mcontext;
+    void* trapPC;
+    void* stackPointer;
+    void* framePointer;
+};
+    
+#elif CPU(X86)
+
+struct SignalContext {
+    SignalContext(mcontext_t&amp; mcontext)
+        : mcontext(mcontext)
+        , trapPC(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__eip))
+        , stackPointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__esp))
+        , framePointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__ebp))
+    {
+        // On X86, SIGTRAP reports the address after the trapping PC. So, dec by 1.
+        trapPC = reinterpret_cast&lt;uint8_t*&gt;(trapPC) - 1;
+    }
+    
+    void adjustPCToPointToTrappingInstruction()
+    {
+        mcontext-&gt;__ss.__eip = reinterpret_cast&lt;uintptr_t&gt;(trapPC);
+    }
+    
+    mcontext_t&amp; mcontext;
+    void* trapPC;
+    void* stackPointer;
+    void* framePointer;
+};
+
+#elif CPU(ARM64) || CPU(ARM_THUMB2) || CPU(ARM)
+    
+struct SignalContext {
+    SignalContext(mcontext_t&amp; mcontext)
+        : mcontext(mcontext)
+        , trapPC(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__pc))
+        , stackPointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__sp))
+#if CPU(ARM64)
+        , framePointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__fp))
+#elif CPU(ARM_THUMB2)
+        , framePointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__r[7]))
+#elif CPU(ARM)
+        , framePointer(reinterpret_cast&lt;void*&gt;(mcontext-&gt;__ss.__r[11]))
+#endif
+    { }
+        
+    void adjustPCToPointToTrappingInstruction() { }
+
+    mcontext_t&amp; mcontext;
+    void* trapPC;
+    void* stackPointer;
+    void* framePointer;
+};
+    
+#endif
+
+inline static bool vmIsInactive(VM&amp; vm)
+{
+    return !vm.entryScope &amp;&amp; !vm.ownerThread();
+}
+
+static Expected&lt;std::pair&lt;VM*, StackBounds&gt;, VMTraps::Error&gt; findActiveVMAndStackBounds(SignalContext&amp; context)
+{
+    VMInspector&amp; inspector = VMInspector::instance();
+    auto locker = tryHoldLock(inspector.getLock());
+    if (UNLIKELY(!locker))
+        return makeUnexpected(VMTraps::Error::LockUnavailable);
+    
+    VM* activeVM = nullptr;
+    StackBounds stackBounds = StackBounds::emptyBounds();
+    void* stackPointer = context.stackPointer;
+    bool unableToAcquireMachineThreadsLock = false;
+    inspector.iterate(locker, [&amp;] (VM&amp; vm) {
+        if (vmIsInactive(vm))
+            return VMInspector::FunctorStatus::Continue;
+
+        auto&amp; machineThreads = vm.heap.machineThreads();
+        auto machineThreadsLocker = tryHoldLock(machineThreads.getLock());
+        if (UNLIKELY(!machineThreadsLocker)) {
+            unableToAcquireMachineThreadsLock = true;
+            return VMInspector::FunctorStatus::Continue; // Try next VM.
+        }
+
+        for (MachineThreads::Thread* thread = machineThreads.threadsListHead(machineThreadsLocker); thread; thread = thread-&gt;next) {
+            RELEASE_ASSERT(thread-&gt;stackBase);
+            RELEASE_ASSERT(thread-&gt;stackEnd);
+            if (stackPointer &lt;= thread-&gt;stackBase &amp;&amp; stackPointer &gt;= thread-&gt;stackEnd) {
+                activeVM = &amp;vm;
+                stackBounds = StackBounds(thread-&gt;stackBase, thread-&gt;stackEnd);
+                return VMInspector::FunctorStatus::Done;
+            }
+        }
+        return VMInspector::FunctorStatus::Continue;
+    });
+
+    if (!activeVM &amp;&amp; unableToAcquireMachineThreadsLock)
+        return makeUnexpected(VMTraps::Error::LockUnavailable);
+    return std::make_pair(activeVM, stackBounds);
+}
+
+static void handleSigusr1(int signalNumber, siginfo_t* info, void* uap)
+{
+    SignalContext context(static_cast&lt;ucontext_t*&gt;(uap)-&gt;uc_mcontext);
+    auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
+    if (activeVMAndStackBounds) {
+        VM* vm = activeVMAndStackBounds.value().first;
+        if (vm) {
+            StackBounds stackBounds = activeVMAndStackBounds.value().second;
+            VMTraps&amp; traps = vm-&gt;traps();
+            if (traps.needTrapHandling())
+                traps.tryInstallTrapBreakpoints(context, stackBounds);
+        }
+    }
+
+    auto originalAction = originalSigusr1Action.sa_sigaction;
+    if (originalAction)
+        originalAction(signalNumber, info, uap);
+}
+
+static void handleSigtrap(int signalNumber, siginfo_t* info, void* uap)
+{
+    SignalContext context(static_cast&lt;ucontext_t*&gt;(uap)-&gt;uc_mcontext);
+    auto activeVMAndStackBounds = findActiveVMAndStackBounds(context);
+    if (!activeVMAndStackBounds)
+        return; // Let the SignalSender try again later.
+
+    VM* vm = activeVMAndStackBounds.value().first;
+    if (vm) {
+        VMTraps&amp; traps = vm-&gt;traps();
+        if (!traps.needTrapHandling())
+            return; // The polling code beat us to handling the trap already.
+
+        auto expectedSuccess = traps.tryJettisonCodeBlocksOnStack(context);
+        if (!expectedSuccess)
+            return; // Let the SignalSender try again later.
+        if (expectedSuccess.value())
+            return; // We've success jettison the codeBlocks.
+    }
+
+    // If we get here, then this SIGTRAP is not due to a VMTrap. Let's do the default action.
+    auto originalAction = originalSigtrapAction.sa_sigaction;
+    if (originalAction) {
+        // It is always safe to just invoke the original handler using the sa_sigaction form
+        // without checking for the SA_SIGINFO flag. If the original handler is of the
+        // sa_handler form, it will just ignore the 2nd and 3rd arguments since sa_handler is a
+        // subset of sa_sigaction. This is what the man pages says the OS does anyway.
+        originalAction(signalNumber, info, uap);
+    }
+    
+    // Pre-emptively restore the default handler but we may roll it back below.
+    struct sigaction currentAction;
+    struct sigaction defaultAction;
+    defaultAction.sa_handler = SIG_DFL;
+    sigfillset(&amp;defaultAction.sa_mask);
+    defaultAction.sa_flags = 0;
+    sigaction(SIGTRAP, &amp;defaultAction, &amp;currentAction);
+    
+    if (currentAction.sa_sigaction != handleSigtrap) {
+        // This means that there's a client handler installed after us. This also means
+        // that the client handler thinks it was able to recover from the SIGTRAP, and
+        // did not uninstall itself. We can't argue with this because the signal isn't
+        // known to be from a VMTraps signal. Hence, restore the client handler
+        // and keep going.
+        sigaction(SIGTRAP, &amp;currentAction, nullptr);
+    }
+}
+
+static void installSignalHandlers()
+{
+    typedef void (* SigactionHandler)(int, siginfo_t *, void *);
+    struct sigaction action;
+
+    action.sa_sigaction = reinterpret_cast&lt;SigactionHandler&gt;(handleSigusr1);
+    sigfillset(&amp;action.sa_mask);
+    action.sa_flags = SA_SIGINFO;
+    sigaction(SIGUSR1, &amp;action, &amp;originalSigusr1Action);
+
+    action.sa_sigaction = reinterpret_cast&lt;SigactionHandler&gt;(handleSigtrap);
+    sigfillset(&amp;action.sa_mask);
+    action.sa_flags = SA_SIGINFO;
+    sigaction(SIGTRAP, &amp;action, &amp;originalSigtrapAction);
+}
+
+ALWAYS_INLINE static CallFrame* sanitizedTopCallFrame(CallFrame* topCallFrame)
+{
+#if !defined(NDEBUG) &amp;&amp; !CPU(ARM) &amp;&amp; !CPU(MIPS)
+    // prepareForExternalCall() in DFGSpeculativeJIT.h may set topCallFrame to a bad word
+    // before calling native functions, but tryInstallTrapBreakpoints() below expects
+    // topCallFrame to be null if not set.
+#if USE(JSVALUE64)
+    const uintptr_t badBeefWord = 0xbadbeef0badbeef;
+#else
+    const uintptr_t badBeefWord = 0xbadbeef;
+#endif
+    if (topCallFrame == reinterpret_cast&lt;CallFrame*&gt;(badBeefWord))
+        topCallFrame = nullptr;
+#endif
+    return topCallFrame;
+}
+
+static bool isSaneFrame(CallFrame* frame, CallFrame* calleeFrame, VMEntryFrame* entryFrame, StackBounds stackBounds)
+{
+    if (reinterpret_cast&lt;void*&gt;(frame) &gt;= reinterpret_cast&lt;void*&gt;(entryFrame))
+        return false;
+    if (calleeFrame &gt;= frame)
+        return false;
+    return stackBounds.contains(frame);
+}
+    
+void VMTraps::tryInstallTrapBreakpoints(SignalContext&amp; context, StackBounds stackBounds)
+{
+    // This must be the initial signal to get the mutator thread's attention.
+    // Let's get the thread to break at invalidation points if needed.
+    VM&amp; vm = this-&gt;vm();
+    void* trapPC = context.trapPC;
+
+    CallFrame* callFrame = reinterpret_cast&lt;CallFrame*&gt;(context.framePointer);
+
+    auto codeBlockSetLocker = tryHoldLock(vm.heap.codeBlockSet().getLock());
+    if (!codeBlockSetLocker)
+        return; // Let the SignalSender try again later.
+
+    {
+        auto allocator = vm.executableAllocator;
+        auto allocatorLocker = tryHoldLock(allocator.getLock());
+        if (!allocatorLocker)
+            return; // Let the SignalSender try again later.
+
+        if (allocator.isValidExecutableMemory(allocatorLocker, trapPC)) {
+            if (vm.isExecutingInRegExpJIT) {
+                // We need to do this because a regExpJIT frame isn't a JS frame.
+                callFrame = sanitizedTopCallFrame(vm.topCallFrame);
+            }
+        } else if (LLInt::isLLIntPC(trapPC)) {
+            // The framePointer probably has the callFrame. We're good to go.
+        } else {
+            // We resort to topCallFrame to see if we can get anything
+            // useful. We usually get here when we're executing C code.
+            callFrame = sanitizedTopCallFrame(vm.topCallFrame);
+        }
+    }
+
+    CodeBlock* foundCodeBlock = nullptr;
+    VMEntryFrame* vmEntryFrame = vm.topVMEntryFrame;
+
+    // We don't have a callee to start with. So, use the end of the stack to keep the
+    // isSaneFrame() checker below happy for the first iteration. It will still check
+    // to ensure that the address is in the stackBounds.
+    CallFrame* calleeFrame = reinterpret_cast&lt;CallFrame*&gt;(stackBounds.end());
+
+    if (!vmEntryFrame || !callFrame)
+        return; // Not running JS code. Let the SignalSender try again later.
+
+    do {
+        if (!isSaneFrame(callFrame, calleeFrame, vmEntryFrame, stackBounds))
+            return; // Let the SignalSender try again later.
+
+        CodeBlock* candidateCodeBlock = callFrame-&gt;codeBlock();
+        if (candidateCodeBlock &amp;&amp; vm.heap.codeBlockSet().contains(codeBlockSetLocker, candidateCodeBlock)) {
+            foundCodeBlock = candidateCodeBlock;
+            break;
+        }
+
+        calleeFrame = callFrame;
+        callFrame = callFrame-&gt;callerFrame(vmEntryFrame);
+
+    } while (callFrame &amp;&amp; vmEntryFrame);
+
+    if (!foundCodeBlock) {
+        // We may have just entered the frame and the codeBlock pointer is not
+        // initialized yet. Just bail and let the SignalSender try again later.
+        return;
+    }
+
+    if (JITCode::isOptimizingJIT(foundCodeBlock-&gt;jitType())) {
+        auto locker = tryHoldLock(m_lock);
+        if (!locker)
+            return; // Let the SignalSender try again later.
+
+        if (!foundCodeBlock-&gt;hasInstalledVMTrapBreakpoints())
+            foundCodeBlock-&gt;installVMTrapBreakpoints();
+        return;
+    }
+}
+
+auto VMTraps::tryJettisonCodeBlocksOnStack(SignalContext&amp; context) -&gt; Expected&lt;bool, Error&gt;
+{
+    VM&amp; vm = this-&gt;vm();
+    auto codeBlockSetLocker = tryHoldLock(vm.heap.codeBlockSet().getLock());
+    if (!codeBlockSetLocker)
+        return makeUnexpected(Error::LockUnavailable);
+
+    CallFrame* topCallFrame = reinterpret_cast&lt;CallFrame*&gt;(context.framePointer);
+    void* trapPC = context.trapPC;
+    bool trapPCIsVMTrap = false;
+    
+    vm.heap.forEachCodeBlockIgnoringJITPlans(codeBlockSetLocker, [&amp;] (CodeBlock* codeBlock) {
+        if (!codeBlock-&gt;hasInstalledVMTrapBreakpoints())
+            return false; // Not found yet.
+
+        JITCode* jitCode = codeBlock-&gt;jitCode().get();
+        ASSERT(JITCode::isOptimizingJIT(jitCode-&gt;jitType()));
+        if (jitCode-&gt;dfgCommon()-&gt;isVMTrapBreakpoint(trapPC)) {
+            trapPCIsVMTrap = true;
+            // At the codeBlock trap point, we're guaranteed that:
+            // 1. the pc is not in the middle of any range of JIT code which invalidation points
+            //    may write over. Hence, it's now safe to patch those invalidation points and
+            //    jettison the codeBlocks.
+            // 2. The top frame must be an optimized JS frame.
+            ASSERT(codeBlock == topCallFrame-&gt;codeBlock());
+            codeBlock-&gt;jettison(Profiler::JettisonDueToVMTraps);
+            return true;
+        }
+
+        return false; // Not found yet.
+    });
+
+    if (!trapPCIsVMTrap)
+        return false;
+
+    invalidateCodeBlocksOnStack(codeBlockSetLocker, topCallFrame);
+
+    // Re-run the trapping instruction now that we've patched it with the invalidation
+    // OSR exit off-ramp.
+    context.adjustPCToPointToTrappingInstruction();
+    return true;
+}
+
+void VMTraps::invalidateCodeBlocksOnStack()
+{
+    invalidateCodeBlocksOnStack(vm().topCallFrame);
+}
+
+void VMTraps::invalidateCodeBlocksOnStack(ExecState* topCallFrame)
+{
+    auto codeBlockSetLocker = holdLock(vm().heap.codeBlockSet().getLock());
+    invalidateCodeBlocksOnStack(codeBlockSetLocker, topCallFrame);
+}
+    
+void VMTraps::invalidateCodeBlocksOnStack(Locker&lt;Lock&gt;&amp;, ExecState* topCallFrame)
+{
+    if (!m_needToInvalidatedCodeBlocks)
+        return;
+
+    m_needToInvalidatedCodeBlocks = false;
+
+    VMEntryFrame* vmEntryFrame = vm().topVMEntryFrame;
+    CallFrame* callFrame = topCallFrame;
+
+    if (!vmEntryFrame)
+        return; // Not running JS code. Nothing to invalidate.
+
+    while (callFrame) {
+        CodeBlock* codeBlock = callFrame-&gt;codeBlock();
+        if (codeBlock &amp;&amp; JITCode::isOptimizingJIT(codeBlock-&gt;jitType()))
+            codeBlock-&gt;jettison(Profiler::JettisonDueToVMTraps);
+        callFrame = callFrame-&gt;callerFrame(vmEntryFrame);
+    }
+}
+
+#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
+
+VMTraps::VMTraps()
+{
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    if (!Options::usePollingTraps()) {
+        static std::once_flag once;
+        std::call_once(once, [] {
+            installSignalHandlers();
+        });
+    }
+#endif
+}
+
+void VMTraps::willDestroyVM()
+{
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    while (!m_signalSenders.isEmpty()) {
+        RefPtr&lt;SignalSender&gt; sender;
+        {
+            // We don't want to be holding the VMTraps lock when calling
+            // SignalSender::willDestroyVM() because SignalSender::willDestroyVM()
+            // will acquire the SignalSender lock, and SignalSender::send() needs
+            // to acquire these locks in the opposite order.
+            auto locker = holdLock(m_lock);
+            sender = m_signalSenders.takeAny();
+        }
+        sender-&gt;willDestroyVM();
+    }
+#endif
+}
+
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+void VMTraps::addSignalSender(VMTraps::SignalSender* sender)
+{
</ins><span class="cx">     auto locker = holdLock(m_lock);
</span><del>-    setTrapForEvent(locker, eventType);
</del><ins>+    m_signalSenders.add(sender);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void VMTraps::removeSignalSender(VMTraps::SignalSender* sender)
+{
+    auto locker = holdLock(m_lock);
+    m_signalSenders.remove(sender);
+}
+
+void VMTraps::SignalSender::willDestroyVM()
+{
+    auto locker = holdLock(m_lock);
+    m_vm = nullptr;
+}
+
+void VMTraps::SignalSender::send()
+{
+    while (true) {
+        // We need a nested scope so that we'll release the lock before we sleep below.
+        {
+            auto locker = holdLock(m_lock);
+            if (!m_vm)
+                break;
+
+            VM&amp; vm = *m_vm;
+            auto optionalOwnerThread = vm.ownerThread();
+            if (optionalOwnerThread) {
+                platformThreadSignal(optionalOwnerThread.value(), SIGUSR1);
+                break;
+            }
+
+            if (vmIsInactive(vm))
+                break;
+
+            VMTraps::Mask mask(m_eventType);
+            if (!vm.needTrapHandling(mask))
+                break;
+        }
+
+        sleepMS(1);
+    }
+
+    auto locker = holdLock(m_lock);
+    if (m_vm)
+        m_vm-&gt;traps().removeSignalSender(this);
+}
+#endif // ENABLE(SIGNAL_BASED_VM_TRAPS)
+
+void VMTraps::fireTrap(VMTraps::EventType eventType)
+{
+    ASSERT(!vm().currentThreadIsHoldingAPILock());
+    {
+        auto locker = holdLock(m_lock);
+        setTrapForEvent(locker, eventType);
+        m_needToInvalidatedCodeBlocks = true;
+    }
+    
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    if (!Options::usePollingTraps()) {
+        // sendSignal() can loop until it has confirmation that the mutator thread
+        // has received the trap request. We'll call it from another trap so that
+        // fireTrap() does not block.
+        RefPtr&lt;SignalSender&gt; sender = adoptRef(new SignalSender(vm(), eventType));
+        addSignalSender(sender.get());
+        createThread(&quot;jsc.vmtraps.signalling.thread&quot;, [sender] {
+            sender-&gt;send();
+        });
+    }
+#endif
+}
+
+void VMTraps::handleTraps(ExecState* exec, VMTraps::Mask mask)
+{
+    VM&amp; vm = this-&gt;vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
+    ASSERT(needTrapHandling(mask));
+    while (needTrapHandling(mask)) {
+        auto eventType = takeTopPriorityTrap(mask);
+        switch (eventType) {
+        case NeedDebuggerBreak:
+            dataLog(&quot;VM &quot;, RawPointer(&amp;vm), &quot; on pid &quot;, getCurrentProcessID(), &quot; received NeedDebuggerBreak trap\n&quot;);
+            invalidateCodeBlocksOnStack(exec);
+            break;
+                
+        case NeedWatchdogCheck:
+            ASSERT(vm.watchdog());
+            if (LIKELY(!vm.watchdog()-&gt;shouldTerminate(exec)))
+                continue;
+            FALLTHROUGH;
+
+        case NeedTermination:
+            invalidateCodeBlocksOnStack(exec);
+            throwException(exec, scope, createTerminatedExecutionException(&amp;vm));
+            return;
+
+        default:
+            RELEASE_ASSERT_NOT_REACHED();
+        }
+    }
+}
+
</ins><span class="cx"> auto VMTraps::takeTopPriorityTrap(VMTraps::Mask mask) -&gt; EventType
</span><span class="cx"> {
</span><span class="cx">     auto locker = holdLock(m_lock);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreruntimeVMTrapsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/runtime/VMTraps.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/runtime/VMTraps.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/runtime/VMTraps.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -25,16 +25,26 @@
</span><span class="cx"> 
</span><span class="cx"> #pragma once
</span><span class="cx"> 
</span><ins>+#include &lt;wtf/Expected.h&gt;
+#include &lt;wtf/HashSet.h&gt;
</ins><span class="cx"> #include &lt;wtf/Lock.h&gt;
</span><span class="cx"> #include &lt;wtf/Locker.h&gt;
</span><ins>+#include &lt;wtf/RefPtr.h&gt;
+#include &lt;wtf/StackBounds.h&gt;
</ins><span class="cx"> 
</span><span class="cx"> namespace JSC {
</span><span class="cx"> 
</span><ins>+class ExecState;
</ins><span class="cx"> class VM;
</span><span class="cx"> 
</span><span class="cx"> class VMTraps {
</span><span class="cx">     typedef uint8_t BitField;
</span><span class="cx"> public:
</span><ins>+    enum class Error {
+        None,
+        LockUnavailable
+    };
+
</ins><span class="cx">     enum EventType {
</span><span class="cx">         // Sorted in servicing priority order from highest to lowest.
</span><span class="cx">         NeedDebuggerBreak,
</span><span class="lines">@@ -75,13 +85,33 @@
</span><span class="cx">         BitField m_mask;
</span><span class="cx">     };
</span><span class="cx"> 
</span><ins>+    VMTraps();
+    ~VMTraps()
+    {
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+        ASSERT(m_signalSenders.isEmpty());
+#endif
+    }
+
+    void willDestroyVM();
+
+    bool needTrapHandling() { return m_needTrapHandling; }
</ins><span class="cx">     bool needTrapHandling(Mask mask) { return m_needTrapHandling &amp; mask.bits(); }
</span><span class="cx">     void* needTrapHandlingAddress() { return &amp;m_needTrapHandling; }
</span><span class="cx"> 
</span><ins>+    void notifyGrabAllLocks()
+    {
+        if (needTrapHandling())
+            invalidateCodeBlocksOnStack();
+    }
+
</ins><span class="cx">     JS_EXPORT_PRIVATE void fireTrap(EventType);
</span><span class="cx"> 
</span><del>-    EventType takeTopPriorityTrap(Mask);
</del><ins>+    void handleTraps(ExecState*, VMTraps::Mask);
</ins><span class="cx"> 
</span><ins>+    void tryInstallTrapBreakpoints(struct SignalContext&amp;, StackBounds);
+    Expected&lt;bool, Error&gt; tryJettisonCodeBlocksOnStack(struct SignalContext&amp;);
+
</ins><span class="cx"> private:
</span><span class="cx">     VM&amp; vm() const;
</span><span class="cx"> 
</span><span class="lines">@@ -101,13 +131,49 @@
</span><span class="cx">         m_trapsBitField &amp;= ~(1 &lt;&lt; eventType);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    EventType takeTopPriorityTrap(Mask);
+
+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    class SignalSender : public ThreadSafeRefCounted&lt;SignalSender&gt; {
+    public:
+        SignalSender(VM&amp; vm, EventType eventType)
+            : m_vm(&amp;vm)
+            , m_eventType(eventType)
+        { }
+
+        void willDestroyVM();
+        void send();
+
+    private:
+        Lock m_lock;
+        VM* m_vm;
+        EventType m_eventType;
+    };
+
+    void invalidateCodeBlocksOnStack();
+    void invalidateCodeBlocksOnStack(ExecState* topCallFrame);
+    void invalidateCodeBlocksOnStack(Locker&lt;Lock&gt;&amp; codeBlockSetLocker, ExecState* topCallFrame);
+
+    void addSignalSender(SignalSender*);
+    void removeSignalSender(SignalSender*);
+#else
+    void invalidateCodeBlocksOnStack() { }
+    void invalidateCodeBlocksOnStack(ExecState*) { }
+#endif
+
</ins><span class="cx">     Lock m_lock;
</span><span class="cx">     union {
</span><span class="cx">         BitField m_needTrapHandling { 0 };
</span><span class="cx">         BitField m_trapsBitField;
</span><span class="cx">     };
</span><ins>+    bool m_needToInvalidatedCodeBlocks { false };
</ins><span class="cx"> 
</span><ins>+#if ENABLE(SIGNAL_BASED_VM_TRAPS)
+    HashSet&lt;RefPtr&lt;SignalSender&gt;&gt; m_signalSenders;
+#endif
+
</ins><span class="cx">     friend class LLIntOffsetsExtractor;
</span><ins>+    friend class SignalSender;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretoolsVMInspectorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tools/VMInspector.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tools/VMInspector.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/tools/VMInspector.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -146,7 +146,7 @@
</span><span class="cx">         // 1. CodeBlocks are added to the CodeBlockSet from the main thread before
</span><span class="cx">         //    they are handed to the JIT plans. Those codeBlocks will have a null jitCode,
</span><span class="cx">         //    but we check for that in our lambda functor.
</span><del>-        // 2. CodeBlockSet::iterate() will acquire the CodeBlockSet lock before iterating.
</del><ins>+        // 2. We will acquire the CodeBlockSet lock before iterating.
</ins><span class="cx">         //    This ensures that a CodeBlock won't be GCed while we're iterating.
</span><span class="cx">         // 3. We do a tryLock on the CodeBlockSet's lock first to ensure that it is
</span><span class="cx">         //    safe for the current thread to lock it before calling
</span><span class="lines">@@ -153,14 +153,15 @@
</span><span class="cx">         //    Heap::forEachCodeBlockIgnoringJITPlans(). Hence, there's no risk of
</span><span class="cx">         //    re-entering the lock and deadlocking on it.
</span><span class="cx"> 
</span><del>-        auto&amp; lock = vm.heap.codeBlockSet().getLock();
-        bool isSafeToLock = ensureIsSafeToLock(lock);
</del><ins>+        auto&amp; codeBlockSetLock = vm.heap.codeBlockSet().getLock();
+        bool isSafeToLock = ensureIsSafeToLock(codeBlockSetLock);
</ins><span class="cx">         if (!isSafeToLock) {
</span><span class="cx">             hasTimeout = true;
</span><span class="cx">             return FunctorStatus::Continue; // Skip this VM.
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        vm.heap.forEachCodeBlockIgnoringJITPlans([&amp;] (CodeBlock* cb) {
</del><ins>+        auto locker = holdLock(codeBlockSetLock);
+        vm.heap.forEachCodeBlockIgnoringJITPlans(locker, [&amp;] (CodeBlock* cb) {
</ins><span class="cx">             JITCode* jitCode = cb-&gt;jitCode().get();
</span><span class="cx">             if (!jitCode) {
</span><span class="cx">                 // If the codeBlock is a replacement codeBlock which is in the process of being
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretoolsVMInspectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/tools/VMInspector.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tools/VMInspector.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/JavaScriptCore/tools/VMInspector.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -46,6 +46,16 @@
</span><span class="cx">     void add(VM*);
</span><span class="cx">     void remove(VM*);
</span><span class="cx"> 
</span><ins>+    Lock&amp; getLock() { return m_lock; }
+
+    enum class FunctorStatus {
+        Continue,
+        Done
+    };
+
+    template &lt;typename Functor&gt;
+    void iterate(const Locker&amp;, const Functor&amp; functor) { iterate(functor); }
+
</ins><span class="cx">     Expected&lt;Locker, Error&gt; lock(Seconds timeout = Seconds::infinity());
</span><span class="cx"> 
</span><span class="cx">     Expected&lt;bool, Error&gt; isValidExecutableMemory(const Locker&amp;, void*);
</span><span class="lines">@@ -52,10 +62,6 @@
</span><span class="cx">     Expected&lt;CodeBlock*, Error&gt; codeBlockForMachinePC(const Locker&amp;, void*);
</span><span class="cx"> 
</span><span class="cx"> private:
</span><del>-    enum class FunctorStatus {
-        Continue,
-        Done
-    };
</del><span class="cx">     template &lt;typename Functor&gt; void iterate(const Functor&amp; functor)
</span><span class="cx">     {
</span><span class="cx">         for (VM* vm = m_list.head(); vm; vm = vm-&gt;next()) {
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WTF/ChangeLog        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2017-03-09  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Make the VM Traps mechanism non-polling for the DFG and FTL.
+        https://bugs.webkit.org/show_bug.cgi?id=168920
+        &lt;rdar://problem/30738588&gt;
+
+        Reviewed by Filip Pizlo.
+
+        Make StackBounds more useful for checking if a pointer is within stack bounds.
+
+        * wtf/MetaAllocator.cpp:
+        (WTF::MetaAllocator::isInAllocatedMemory):
+        * wtf/MetaAllocator.h:
+        * wtf/Platform.h:
+        * wtf/StackBounds.h:
+        (WTF::StackBounds::emptyBounds):
+        (WTF::StackBounds::StackBounds):
+        (WTF::StackBounds::isEmpty):
+        (WTF::StackBounds::contains):
+
</ins><span class="cx"> 2017-03-07  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WTF should make it super easy to do ARM concurrency tricks
</span></span></pre></div>
<a id="trunkSourceWTFwtfMetaAllocatorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MetaAllocator.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MetaAllocator.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WTF/wtf/MetaAllocator.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -426,7 +426,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-bool MetaAllocator::isInAllocatedMemory(const LockHolder&amp;, void* address)
</del><ins>+bool MetaAllocator::isInAllocatedMemory(const AbstractLocker&amp;, void* address)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(m_lock.isLocked());
</span><span class="cx">     uintptr_t page = reinterpret_cast&lt;uintptr_t&gt;(address) &gt;&gt; m_logPageSize;
</span></span></pre></div>
<a id="trunkSourceWTFwtfMetaAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/MetaAllocator.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/MetaAllocator.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WTF/wtf/MetaAllocator.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -98,7 +98,7 @@
</span><span class="cx">     WTF_EXPORT_PRIVATE size_t debugFreeSpaceSize();
</span><span class="cx"> 
</span><span class="cx">     Lock&amp; getLock() { return m_lock; }
</span><del>-    WTF_EXPORT_PRIVATE bool isInAllocatedMemory(const LockHolder&amp;, void* address);
</del><ins>+    WTF_EXPORT_PRIVATE bool isInAllocatedMemory(const AbstractLocker&amp;, void* address);
</ins><span class="cx">     
</span><span class="cx"> #if ENABLE(META_ALLOCATOR_PROFILE)
</span><span class="cx">     void dumpProfile();
</span></span></pre></div>
<a id="trunkSourceWTFwtfPlatformh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/Platform.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/Platform.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WTF/wtf/Platform.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2006-2009, 2013-2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2006-2017 Apple Inc. All rights reserved.
</ins><span class="cx">  * Copyright (C) 2007-2009 Torch Mobile, Inc.
</span><span class="cx">  * Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
</span><span class="cx">  *
</span><span class="lines">@@ -913,6 +913,10 @@
</span><span class="cx"> #endif
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><ins>+#if OS(DARWIN) &amp;&amp; ENABLE(JIT)
+#define ENABLE_SIGNAL_BASED_VM_TRAPS 1
+#endif
+
</ins><span class="cx"> /* CSS Selector JIT Compiler */
</span><span class="cx"> #if !defined(ENABLE_CSS_SELECTOR_JIT)
</span><span class="cx"> #if (CPU(X86_64) || CPU(ARM64) || (CPU(ARM_THUMB2) &amp;&amp; PLATFORM(IOS))) &amp;&amp; ENABLE(JIT) &amp;&amp; (OS(DARWIN) || PLATFORM(GTK))
</span></span></pre></div>
<a id="trunkSourceWTFwtfStackBoundsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/StackBounds.h (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/StackBounds.h        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WTF/wtf/StackBounds.h        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2010, 2013 Apple Inc. All Rights Reserved.
</del><ins>+ * Copyright (C) 2010-2017 Apple Inc. All Rights Reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx">     const static size_t s_defaultAvailabilityDelta = 64 * 1024;
</span><span class="cx"> 
</span><span class="cx"> public:
</span><ins>+    static StackBounds emptyBounds() { return StackBounds(); }
+
</ins><span class="cx">     static StackBounds currentThreadStackBounds()
</span><span class="cx">     {
</span><span class="cx">         StackBounds bounds;
</span><span class="lines">@@ -48,6 +50,13 @@
</span><span class="cx">         return bounds;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    StackBounds(void* origin, void* end)
+        : m_origin(origin)
+        , m_bound(end)
+    {
+        checkConsistency();
+    }
+
</ins><span class="cx">     void* origin() const
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_origin);
</span><span class="lines">@@ -67,6 +76,17 @@
</span><span class="cx">         return static_cast&lt;char*&gt;(m_bound) - static_cast&lt;char*&gt;(m_origin);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    bool isEmpty() const { return !m_origin; }
+
+    bool contains(void* p) const
+    {
+        if (isEmpty())
+            return false;
+        if (isGrowingDownward())
+            return (m_origin &gt;= p) &amp;&amp; (p &gt; m_bound);
+        return (m_bound &gt; p) &amp;&amp; (p &gt;= m_origin);
+    }
+
</ins><span class="cx">     void* recursionLimit(size_t minAvailableDelta = s_defaultAvailabilityDelta) const
</span><span class="cx">     {
</span><span class="cx">         checkConsistency();
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WebCore/ChangeLog        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-03-09  Mark Lam  &lt;mark.lam@apple.com&gt;
+
+        Make the VM Traps mechanism non-polling for the DFG and FTL.
+        https://bugs.webkit.org/show_bug.cgi?id=168920
+        &lt;rdar://problem/30738588&gt;
+
+        Reviewed by Filip Pizlo.
+
+        No new tests needed.  This is covered by existing tests.
+
+        * bindings/js/WorkerScriptController.cpp:
+        (WebCore::WorkerScriptController::WorkerScriptController):
+        (WebCore::WorkerScriptController::scheduleExecutionTermination):
+
</ins><span class="cx"> 2017-03-08  Dean Jackson  &lt;dino@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebGPU: Backend - Library and Functions
</span></span></pre></div>
<a id="trunkSourceWebCorebindingsjsWorkerScriptControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp (213651 => 213652)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp        2017-03-09 19:08:37 UTC (rev 213651)
+++ trunk/Source/WebCore/bindings/js/WorkerScriptController.cpp        2017-03-09 19:08:46 UTC (rev 213652)
</span><span class="lines">@@ -51,7 +51,6 @@
</span><span class="cx">     , m_workerGlobalScopeWrapper(*m_vm)
</span><span class="cx"> {
</span><span class="cx">     m_vm-&gt;heap.acquireAccess(); // It's not clear that we have good discipline for heap access, so turn it on permanently.
</span><del>-    m_vm-&gt;setNeedAsynchronousTerminationSupport();
</del><span class="cx">     JSVMClientData::initNormalWorld(m_vm.get());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -151,11 +150,13 @@
</span><span class="cx"> 
</span><span class="cx"> void WorkerScriptController::scheduleExecutionTermination()
</span><span class="cx"> {
</span><del>-    // The mutex provides a memory barrier to ensure that once
-    // termination is scheduled, isTerminatingExecution() will
-    // accurately reflect that state when called from another thread.
-    LockHolder locker(m_scheduledTerminationMutex);
-    m_isTerminatingExecution = true;
</del><ins>+    {
+        // The mutex provides a memory barrier to ensure that once
+        // termination is scheduled, isTerminatingExecution() will
+        // accurately reflect that state when called from another thread.
+        LockHolder locker(m_scheduledTerminationMutex);
+        m_isTerminatingExecution = true;
+    }
</ins><span class="cx">     m_vm-&gt;notifyNeedTermination();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>