Add support for selective handling of VM traps.
authormark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Mar 2017 20:35:37 +0000 (20:35 +0000)
committermark.lam@apple.com <mark.lam@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 2 Mar 2017 20:35:37 +0000 (20:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=169087

Reviewed by Keith Miller.

This is needed because there are some places in the VM where it's appropriate to
handle some types of VM traps but not others.

We implement this selection by using a VMTraps::Mask that allows the user to
specify which traps should be serviced.

* interpreter/Interpreter.cpp:
(JSC::Interpreter::executeProgram):
(JSC::Interpreter::executeCall):
(JSC::Interpreter::executeConstruct):
(JSC::Interpreter::execute):
* runtime/VM.cpp:
(JSC::VM::handleTraps):
* runtime/VM.h:
* runtime/VMTraps.cpp:
(JSC::VMTraps::takeTrap): Deleted.
* runtime/VMTraps.h:
(JSC::VMTraps::Mask::Mask):
(JSC::VMTraps::Mask::allEventTypes):
(JSC::VMTraps::Mask::bits):
(JSC::VMTraps::Mask::init):
(JSC::VMTraps::needTrapHandling):
(JSC::VMTraps::hasTrapForEvent):

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

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/runtime/VM.cpp
Source/JavaScriptCore/runtime/VM.h
Source/JavaScriptCore/runtime/VMTraps.cpp
Source/JavaScriptCore/runtime/VMTraps.h

index 8872a5e..9468ef4 100644 (file)
@@ -1,3 +1,34 @@
+2017-03-02  Mark Lam  <mark.lam@apple.com>
+
+        Add support for selective handling of VM traps.
+        https://bugs.webkit.org/show_bug.cgi?id=169087
+
+        Reviewed by Keith Miller.
+
+        This is needed because there are some places in the VM where it's appropriate to
+        handle some types of VM traps but not others.
+
+        We implement this selection by using a VMTraps::Mask that allows the user to
+        specify which traps should be serviced.
+
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::executeProgram):
+        (JSC::Interpreter::executeCall):
+        (JSC::Interpreter::executeConstruct):
+        (JSC::Interpreter::execute):
+        * runtime/VM.cpp:
+        (JSC::VM::handleTraps):
+        * runtime/VM.h:
+        * runtime/VMTraps.cpp:
+        (JSC::VMTraps::takeTrap): Deleted.
+        * runtime/VMTraps.h:
+        (JSC::VMTraps::Mask::Mask):
+        (JSC::VMTraps::Mask::allEventTypes):
+        (JSC::VMTraps::Mask::bits):
+        (JSC::VMTraps::Mask::init):
+        (JSC::VMTraps::needTrapHandling):
+        (JSC::VMTraps::hasTrapForEvent):
+
 2017-03-02  Alex Christensen  <achristensen@webkit.org>
 
         Continue enabling WebRTC
index f28d837..bdf068c 100644 (file)
@@ -861,7 +861,8 @@ failedJSONP:
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -921,7 +922,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
         newCodeBlock = 0;
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -986,7 +988,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
         newCodeBlock = 0;
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1050,7 +1053,8 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
     StackStats::CheckPoint stackCheckPoint;
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(closure.oldCallFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(closure.oldCallFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1153,7 +1157,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1194,7 +1199,8 @@ JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* cal
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
index 7446788..68ed1dd 100644 (file)
@@ -946,14 +946,17 @@ void VM::verifyExceptionCheckNeedIsSatisfied(unsigned recursionDepth, ExceptionE
 }
 #endif
 
-void VM::handleTraps(ExecState* exec)
+void VM::handleTraps(ExecState* exec, VMTraps::Mask mask)
 {
     auto scope = DECLARE_THROW_SCOPE(*this);
 
-    ASSERT(needTrapHandling());
-    while (needTrapHandling()) {
-        auto trapEventType = m_traps.takeTopPriorityTrap();
+    ASSERT(needTrapHandling(mask));
+    while (needTrapHandling(mask)) {
+        auto trapEventType = m_traps.takeTopPriorityTrap(mask);
         switch (trapEventType) {
+        case VMTraps::NeedDebuggerBreak:
+            RELEASE_ASSERT_NOT_REACHED();
+
         case VMTraps::NeedWatchdogCheck:
             ASSERT(m_watchdog);
             if (LIKELY(!m_watchdog->shouldTerminate(exec)))
index 1a4f902..cb5757f 100644 (file)
@@ -671,9 +671,9 @@ public:
     template<typename Func>
     void logEvent(CodeBlock*, const char* summary, const Func& func);
 
-    void handleTraps(ExecState*);
+    void handleTraps(ExecState*, VMTraps::Mask = VMTraps::Mask::allEventTypes());
 
-    bool needTrapHandling() { return m_traps.needTrapHandling(); }
+    bool needTrapHandling(VMTraps::Mask mask = VMTraps::Mask::allEventTypes()) { return m_traps.needTrapHandling(mask); }
     void* needTrapHandlingAddress() { return m_traps.needTrapHandlingAddress(); }
 
     void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
index 581e4ab..60b76dd 100644 (file)
@@ -34,22 +34,15 @@ void VMTraps::fireTrap(VMTraps::EventType eventType)
     setTrapForEvent(locker, eventType);
 }
 
-bool VMTraps::takeTrap(VMTraps::EventType eventType)
+auto VMTraps::takeTopPriorityTrap(VMTraps::Mask mask) -> EventType
 {
     auto locker = holdLock(m_lock);
-    if (hasTrapForEvent(locker, eventType)) {
-        clearTrapForEvent(locker, eventType);
-        return true;
-    }
-    return false;
-}
-
-auto VMTraps::takeTopPriorityTrap() -> EventType
-{
     for (int i = 0; i < NumberOfEventTypes; ++i) {
         EventType eventType = static_cast<EventType>(i);
-        if (takeTrap(eventType))
+        if (hasTrapForEvent(locker, eventType, mask)) {
+            clearTrapForEvent(locker, eventType);
             return eventType;
+        }
     }
     return Invalid;
 }
index 32cbaaf..e77c642 100644 (file)
@@ -33,30 +33,62 @@ namespace JSC {
 class VM;
 
 class VMTraps {
+    typedef uint8_t BitField;
 public:
     enum EventType {
         // Sorted in servicing priority order from highest to lowest.
+        NeedDebuggerBreak,
         NeedTermination,
         NeedWatchdogCheck,
         NumberOfEventTypes, // This entry must be last in this list.
         Invalid
     };
 
-    bool needTrapHandling() { return m_needTrapHandling; }
+    class Mask {
+    public:
+        enum AllEventTypes { AllEventTypesTag };
+        Mask(AllEventTypes)
+            : m_mask(std::numeric_limits<BitField>::max())
+        { }
+        static Mask allEventTypes() { return Mask(AllEventTypesTag); }
+
+        template<typename... Arguments>
+        Mask(Arguments... args)
+            : m_mask(0)
+        {
+            init(args...);
+        }
+
+        BitField bits() const { return m_mask; }
+
+    private:
+        template<typename... Arguments>
+        void init(EventType eventType, Arguments... args)
+        {
+            ASSERT(eventType < NumberOfEventTypes);
+            m_mask |= (1 << eventType);
+            init(args...);
+        }
+
+        void init() { }
+
+        BitField m_mask;
+    };
+
+    bool needTrapHandling(Mask mask) { return m_needTrapHandling & mask.bits(); }
     void* needTrapHandlingAddress() { return &m_needTrapHandling; }
 
     JS_EXPORT_PRIVATE void fireTrap(EventType);
 
-    bool takeTrap(EventType);
-    EventType takeTopPriorityTrap();
+    EventType takeTopPriorityTrap(Mask);
 
 private:
     VM& vm() const;
 
-    bool hasTrapForEvent(Locker<Lock>&, EventType eventType)
+    bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask)
     {
         ASSERT(eventType < NumberOfEventTypes);
-        return (m_trapsBitField & (1 << eventType));
+        return (m_trapsBitField & mask.bits() & (1 << eventType));
     }
     void setTrapForEvent(Locker<Lock>&, EventType eventType)
     {
@@ -71,8 +103,8 @@ private:
 
     Lock m_lock;
     union {
-        uint8_t m_needTrapHandling { false };
-        uint8_t m_trapsBitField;
+        BitField m_needTrapHandling { 0 };
+        BitField m_trapsBitField;
     };
 
     friend class LLIntOffsetsExtractor;