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 CallFrame;
40class JSGlobalObject;
41class VM;
42
43class VMTraps {
44 typedef uint8_t BitField;
45public:
46 enum class Error {
47 None,
48 LockUnavailable,
49 NotJITCode
50 };
51
52 enum EventType {
53 // Sorted in servicing priority order from highest to lowest.
54 NeedDebuggerBreak,
55 NeedTermination,
56 NeedWatchdogCheck,
57 NumberOfEventTypes, // This entry must be last in this list.
58 Invalid
59 };
60
61 class Mask {
62 public:
63 enum AllEventTypes { AllEventTypesTag };
64 Mask(AllEventTypes)
65 : m_mask(std::numeric_limits<BitField>::max())
66 { }
67 static Mask allEventTypes() { return Mask(AllEventTypesTag); }
68
69 template<typename... Arguments>
70 Mask(Arguments... args)
71 : m_mask(0)
72 {
73 init(args...);
74 }
75
76 BitField bits() const { return m_mask; }
77
78 private:
79 template<typename... Arguments>
80 void init(EventType eventType, Arguments... args)
81 {
82 ASSERT(eventType < NumberOfEventTypes);
83 m_mask |= (1 << eventType);
84 init(args...);
85 }
86
87 void init() { }
88
89 BitField m_mask;
90 };
91
92 ~VMTraps();
93 VMTraps();
94
95 void willDestroyVM();
96
97 bool needTrapHandling() { return m_needTrapHandling; }
98 bool needTrapHandling(Mask mask) { return m_needTrapHandling & mask.bits(); }
99 void* needTrapHandlingAddress() { return &m_needTrapHandling; }
100
101 void notifyGrabAllLocks()
102 {
103 if (needTrapHandling())
104 invalidateCodeBlocksOnStack();
105 }
106
107 JS_EXPORT_PRIVATE void fireTrap(EventType);
108
109 void handleTraps(JSGlobalObject*, CallFrame*, VMTraps::Mask);
110
111 void tryInstallTrapBreakpoints(struct SignalContext&, StackBounds);
112
113private:
114 VM& vm() const;
115
116 bool hasTrapForEvent(Locker<Lock>&, EventType eventType, Mask mask)
117 {
118 ASSERT(eventType < NumberOfEventTypes);
119 return (m_trapsBitField & mask.bits() & (1 << eventType));
120 }
121 void setTrapForEvent(Locker<Lock>&, EventType eventType)
122 {
123 ASSERT(eventType < NumberOfEventTypes);
124 m_trapsBitField |= (1 << eventType);
125 }
126 void clearTrapForEvent(Locker<Lock>&, EventType eventType)
127 {
128 ASSERT(eventType < NumberOfEventTypes);
129 m_trapsBitField &= ~(1 << eventType);
130 }
131
132 EventType takeTopPriorityTrap(Mask);
133
134#if ENABLE(SIGNAL_BASED_VM_TRAPS)
135 class SignalSender;
136 friend class SignalSender;
137
138 void invalidateCodeBlocksOnStack();
139 void invalidateCodeBlocksOnStack(CallFrame* topCallFrame);
140 void invalidateCodeBlocksOnStack(Locker<Lock>& codeBlockSetLocker, CallFrame* topCallFrame);
141
142 void addSignalSender(SignalSender*);
143 void removeSignalSender(SignalSender*);
144#else
145 void invalidateCodeBlocksOnStack() { }
146 void invalidateCodeBlocksOnStack(CallFrame*) { }
147#endif
148
149 Box<Lock> m_lock;
150 Ref<AutomaticThreadCondition> m_condition;
151 union {
152 BitField m_needTrapHandling { 0 };
153 BitField m_trapsBitField;
154 };
155 bool m_needToInvalidatedCodeBlocks { false };
156 bool m_isShuttingDown { false };
157
158#if ENABLE(SIGNAL_BASED_VM_TRAPS)
159 RefPtr<SignalSender> m_signalSender;
160#endif
161
162 friend class LLIntOffsetsExtractor;
163 friend class SignalSender;
164};
165
166} // namespace JSC
167