1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include <wtf/AutomaticThread.h>
29#include <wtf/Box.h>
30#include <wtf/Expected.h>
31#include <wtf/HashSet.h>
32#include <wtf/Lock.h>
33#include <wtf/Locker.h>
34#include <wtf/RefPtr.h>
35#include <wtf/StackBounds.h>
36
37namespace JSC {
38
39class ExecState;
40class VM;
41
42class VMTraps {
43 typedef uint8_t BitField;
44public:
45 enum class Error {
46 None,
47 LockUnavailable,
48 NotJITCode
49 };
50
51 enum EventType {
52 // Sorted in servicing priority order from highest to lowest.
53 NeedDebuggerBreak,
54 NeedTermination,
55 NeedWatchdogCheck,
56 NumberOfEventTypes, // This entry must be last in this list.
57 Invalid
58 };
59
60 class Mask {
61 public:
62 enum AllEventTypes { AllEventTypesTag };
63 Mask(AllEventTypes)
64 : m_mask(std::numeric_limits<BitField>::max())
65 { }
66 static Mask allEventTypes() { return Mask(AllEventTypesTag); }
67
68 template<typename... Arguments>
69 Mask(Arguments... args)
70 : m_mask(0)
71 {
72 init(args...);
73 }
74
75 BitField bits() const { return m_mask; }
76
77 private:
78 template<typename... Arguments>
79 void init(EventType eventType, Arguments... args)
80 {
81 ASSERT(eventType < NumberOfEventTypes);
82 m_mask |= (1 << eventType);
83 init(args...);
84 }
85
86 void init() { }
87
88 BitField m_mask;
89 };
90
91 ~VMTraps();
92 VMTraps();
93
94 void willDestroyVM();
95
96 bool needTrapHandling() { return m_needTrapHandling; }
97 bool needTrapHandling(Mask mask) { return m_needTrapHandling & mask.bits(); }
98 void* needTrapHandlingAddress() { return &m_needTrapHandling; }
99
100 void notifyGrabAllLocks()
101 {
102 if (needTrapHandling())
103 invalidateCodeBlocksOnStack();
104 }
105
106 JS_EXPORT_PRIVATE void fireTrap(EventType);
107
108 void handleTraps(ExecState*, VMTraps::Mask);
109
110 void tryInstallTrapBreakpoints(struct SignalContext&, StackBounds);
111
112private:
113 VM& vm() const;
114
115 bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask)
116 {
117 ASSERT(eventType < NumberOfEventTypes);
118 return (m_trapsBitField & mask.bits() & (1 << eventType));
119 }
120 void setTrapForEvent(Locker<Lock>&, EventType eventType)
121 {
122 ASSERT(eventType < NumberOfEventTypes);
123 m_trapsBitField |= (1 << eventType);
124 }
125 void clearTrapForEvent(Locker<Lock>&, EventType eventType)
126 {
127 ASSERT(eventType < NumberOfEventTypes);
128 m_trapsBitField &= ~(1 << eventType);
129 }
130
131 EventType takeTopPriorityTrap(Mask);
132
133#if ENABLE(SIGNAL_BASED_VM_TRAPS)
134 class SignalSender;
135 friend class SignalSender;
136
137 void invalidateCodeBlocksOnStack();
138 void invalidateCodeBlocksOnStack(ExecState* topCallFrame);
139 void invalidateCodeBlocksOnStack(Locker<Lock>& codeBlockSetLocker, ExecState* topCallFrame);
140
141 void addSignalSender(SignalSender*);
142 void removeSignalSender(SignalSender*);
143#else
144 void invalidateCodeBlocksOnStack() { }
145 void invalidateCodeBlocksOnStack(ExecState*) { }
146#endif
147
148 Box<Lock> m_lock;
149 Ref<AutomaticThreadCondition> m_condition;
150 union {
151 BitField m_needTrapHandling { 0 };
152 BitField m_trapsBitField;
153 };
154 bool m_needToInvalidatedCodeBlocks { false };
155 bool m_isShuttingDown { false };
156
157#if ENABLE(SIGNAL_BASED_VM_TRAPS)
158 RefPtr<SignalSender> m_signalSender;
159#endif
160
161 friend class LLIntOffsetsExtractor;
162 friend class SignalSender;
163};
164
165} // namespace JSC
166