Make the VM Traps mechanism non-polling for the DFG and FTL.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 19:08:46 +0000 (19:08 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 9 Mar 2017 19:08:46 +0000 (19:08 +0000)
commitb3b98fa31c3adf510cf24e14887584a70395d207
tree0b13a9303e3b6f407346ec009bcbf135296f6132
parentb55daab8f9372d3255be633aeb9a9ef3690966ab
Make the VM Traps mechanism non-polling for the DFG and FTL.
https://bugs.webkit.org/show_bug.cgi?id=168920
<rdar://problem/30738588>

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):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@213652 268f45cc-cd09-0410-ab3c-d52691b4dbfc
47 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/assembler/ARM64Assembler.h
Source/JavaScriptCore/assembler/ARMAssembler.h
Source/JavaScriptCore/assembler/ARMv7Assembler.h
Source/JavaScriptCore/assembler/MIPSAssembler.h
Source/JavaScriptCore/assembler/MacroAssemblerARM.h
Source/JavaScriptCore/assembler/MacroAssemblerARM64.h
Source/JavaScriptCore/assembler/MacroAssemblerARMv7.h
Source/JavaScriptCore/assembler/MacroAssemblerMIPS.h
Source/JavaScriptCore/assembler/MacroAssemblerX86Common.h
Source/JavaScriptCore/assembler/X86Assembler.h
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/dfg/DFGCommonData.cpp
Source/JavaScriptCore/dfg/DFGCommonData.h
Source/JavaScriptCore/dfg/DFGJumpReplacement.cpp
Source/JavaScriptCore/dfg/DFGJumpReplacement.h
Source/JavaScriptCore/dfg/DFGNodeType.h
Source/JavaScriptCore/heap/CodeBlockSet.cpp
Source/JavaScriptCore/heap/CodeBlockSet.h
Source/JavaScriptCore/heap/CodeBlockSetInlines.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/heap/HeapInlines.h
Source/JavaScriptCore/heap/MachineStackMarker.h
Source/JavaScriptCore/jit/ExecutableAllocator.cpp
Source/JavaScriptCore/jit/ExecutableAllocator.h
Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp
Source/JavaScriptCore/profiler/ProfilerJettisonReason.h
Source/JavaScriptCore/runtime/JSLock.cpp
Source/JavaScriptCore/runtime/Options.cpp
Source/JavaScriptCore/runtime/Options.h
Source/JavaScriptCore/runtime/PlatformThread.h
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/runtime/VMTraps.cpp
Source/JavaScriptCore/runtime/VMTraps.h
Source/JavaScriptCore/tools/VMInspector.cpp
Source/JavaScriptCore/tools/VMInspector.h
Source/WTF/ChangeLog
Source/WTF/wtf/MetaAllocator.cpp
Source/WTF/wtf/MetaAllocator.h
Source/WTF/wtf/Platform.h
Source/WTF/wtf/StackBounds.h
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/WorkerScriptController.cpp