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 8872a5e1481f1324f5f301c8643105e348349998..9468ef4d7bd020c7cab161f0304479bc89d4e091 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
 2017-03-02  Alex Christensen  <achristensen@webkit.org>
 
         Continue enabling WebRTC
index f28d83789e75d5722d00e4b1193dab478d85b5f8..bdf068cc29ad012a758db494586827f8263e0c2b 100644 (file)
@@ -861,7 +861,8 @@ failedJSONP:
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -921,7 +922,8 @@ JSValue Interpreter::executeCall(CallFrame* callFrame, JSObject* function, CallT
         newCodeBlock = 0;
 
     if (UNLIKELY(vm.needTrapHandling())) {
         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());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -986,7 +988,8 @@ JSObject* Interpreter::executeConstruct(CallFrame* callFrame, JSObject* construc
         newCodeBlock = 0;
 
     if (UNLIKELY(vm.needTrapHandling())) {
         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());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1050,7 +1053,8 @@ JSValue Interpreter::execute(CallFrameClosure& closure)
     StackStats::CheckPoint stackCheckPoint;
 
     if (UNLIKELY(vm.needTrapHandling())) {
     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());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1153,7 +1157,8 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
@@ -1194,7 +1199,8 @@ JSValue Interpreter::execute(ModuleProgramExecutable* executable, CallFrame* cal
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
     }
 
     if (UNLIKELY(vm.needTrapHandling())) {
-        vm.handleTraps(callFrame);
+        VMTraps::Mask mask(VMTraps::NeedTermination, VMTraps::NeedWatchdogCheck);
+        vm.handleTraps(callFrame, mask);
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
         RETURN_IF_EXCEPTION(throwScope, throwScope.exception());
     }
 
index 7446788d29887be475cfc7a288b80f0b96dfc508..68ed1ddfe29055bf890a7bdf62666cb0e35e8f5a 100644 (file)
@@ -946,14 +946,17 @@ void VM::verifyExceptionCheckNeedIsSatisfied(unsigned recursionDepth, ExceptionE
 }
 #endif
 
 }
 #endif
 
-void VM::handleTraps(ExecState* exec)
+void VM::handleTraps(ExecState* exec, VMTraps::Mask mask)
 {
     auto scope = DECLARE_THROW_SCOPE(*this);
 
 {
     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) {
         switch (trapEventType) {
+        case VMTraps::NeedDebuggerBreak:
+            RELEASE_ASSERT_NOT_REACHED();
+
         case VMTraps::NeedWatchdogCheck:
             ASSERT(m_watchdog);
             if (LIKELY(!m_watchdog->shouldTerminate(exec)))
         case VMTraps::NeedWatchdogCheck:
             ASSERT(m_watchdog);
             if (LIKELY(!m_watchdog->shouldTerminate(exec)))
index 1a4f90228488479b6805ab3e0f4d0afbe89052aa..cb5757fad61d2d14cf4b40d584289f39527ca16f 100644 (file)
@@ -671,9 +671,9 @@ public:
     template<typename Func>
     void logEvent(CodeBlock*, const char* summary, const Func& func);
 
     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); }
     void* needTrapHandlingAddress() { return m_traps.needTrapHandlingAddress(); }
 
     void notifyNeedTermination() { m_traps.fireTrap(VMTraps::NeedTermination); }
index 581e4abd69f1943aa184f73298f9a6f4b5370e53..60b76dd9c732cbcd5983131909c3f6f8c09322f2 100644 (file)
@@ -34,22 +34,15 @@ void VMTraps::fireTrap(VMTraps::EventType eventType)
     setTrapForEvent(locker, eventType);
 }
 
     setTrapForEvent(locker, eventType);
 }
 
-bool VMTraps::takeTrap(VMTraps::EventType eventType)
+auto VMTraps::takeTopPriorityTrap(VMTraps::Mask mask) -> EventType
 {
     auto locker = holdLock(m_lock);
 {
     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);
     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 eventType;
+        }
     }
     return Invalid;
 }
     }
     return Invalid;
 }
index 32cbaaf2698d1fa2066ee1f491c6fa512db490f2..e77c64245601b4c41abf574cc44aba9984b033fd 100644 (file)
@@ -33,30 +33,62 @@ namespace JSC {
 class VM;
 
 class VMTraps {
 class VM;
 
 class VMTraps {
+    typedef uint8_t BitField;
 public:
     enum EventType {
         // Sorted in servicing priority order from highest to lowest.
 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
     };
 
         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);
 
     void* needTrapHandlingAddress() { return &m_needTrapHandling; }
 
     JS_EXPORT_PRIVATE void fireTrap(EventType);
 
-    bool takeTrap(EventType);
-    EventType takeTopPriorityTrap();
+    EventType takeTopPriorityTrap(Mask);
 
 private:
     VM& vm() const;
 
 
 private:
     VM& vm() const;
 
-    bool hasTrapForEvent(Locker<Lock>&, EventType eventType)
+    bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask)
     {
         ASSERT(eventType < NumberOfEventTypes);
     {
         ASSERT(eventType < NumberOfEventTypes);
-        return (m_trapsBitField & (1 << eventType));
+        return (m_trapsBitField & mask.bits() & (1 << eventType));
     }
     void setTrapForEvent(Locker<Lock>&, EventType eventType)
     {
     }
     void setTrapForEvent(Locker<Lock>&, EventType eventType)
     {
@@ -71,8 +103,8 @@ private:
 
     Lock m_lock;
     union {
 
     Lock m_lock;
     union {
-        uint8_t m_needTrapHandling { false };
-        uint8_t m_trapsBitField;
+        BitField m_needTrapHandling { 0 };
+        BitField m_trapsBitField;
     };
 
     friend class LLIntOffsetsExtractor;
     };
 
     friend class LLIntOffsetsExtractor;