Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_EXECUTION_H_
6 : #define V8_EXECUTION_H_
7 :
8 : #include "src/allocation.h"
9 : #include "src/base/atomicops.h"
10 : #include "src/globals.h"
11 : #include "src/utils.h"
12 :
13 : namespace v8 {
14 : namespace internal {
15 :
16 : template <typename T>
17 : class Handle;
18 :
19 : class Execution final : public AllStatic {
20 : public:
21 : // Whether to report pending messages, or keep them pending on the isolate.
22 : enum class MessageHandling { kReport, kKeepPending };
23 :
24 : // Call a function, the caller supplies a receiver and an array
25 : // of arguments.
26 : //
27 : // When the function called is not in strict mode, receiver is
28 : // converted to an object.
29 : //
30 : V8_EXPORT_PRIVATE MUST_USE_RESULT static MaybeHandle<Object> Call(
31 : Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
32 : int argc, Handle<Object> argv[]);
33 :
34 : // Construct object from function, the caller supplies an array of
35 : // arguments.
36 : MUST_USE_RESULT static MaybeHandle<Object> New(Isolate* isolate,
37 : Handle<Object> constructor,
38 : int argc,
39 : Handle<Object> argv[]);
40 : MUST_USE_RESULT static MaybeHandle<Object> New(Isolate* isolate,
41 : Handle<Object> constructor,
42 : Handle<Object> new_target,
43 : int argc,
44 : Handle<Object> argv[]);
45 :
46 : // Call a function, just like Call(), but handle don't report exceptions
47 : // externally.
48 : // The return value is either the result of calling the function (if no
49 : // exception occurred), or an empty handle.
50 : // If message_handling is MessageHandling::kReport, exceptions (except for
51 : // termination exceptions) will be stored in exception_out (if not a
52 : // nullptr).
53 : static MaybeHandle<Object> TryCall(Isolate* isolate, Handle<Object> callable,
54 : Handle<Object> receiver, int argc,
55 : Handle<Object> argv[],
56 : MessageHandling message_handling,
57 : MaybeHandle<Object>* exception_out);
58 : };
59 :
60 :
61 : class ExecutionAccess;
62 : class PostponeInterruptsScope;
63 :
64 :
65 : // StackGuard contains the handling of the limits that are used to limit the
66 : // number of nested invocations of JavaScript and the stack size used in each
67 : // invocation.
68 : class V8_EXPORT_PRIVATE StackGuard final {
69 : public:
70 : // Pass the address beyond which the stack should not grow. The stack
71 : // is assumed to grow downwards.
72 : void SetStackLimit(uintptr_t limit);
73 :
74 : // The simulator uses a separate JS stack. Limits on the JS stack might have
75 : // to be adjusted in order to reflect overflows of the C stack, because we
76 : // cannot rely on the interleaving of frames on the simulator.
77 : void AdjustStackLimitForSimulator();
78 :
79 : // Threading support.
80 : char* ArchiveStackGuard(char* to);
81 : char* RestoreStackGuard(char* from);
82 : static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
83 : void FreeThreadResources();
84 : // Sets up the default stack guard for this thread if it has not
85 : // already been set up.
86 : void InitThread(const ExecutionAccess& lock);
87 : // Clears the stack guard for this thread so it does not look as if
88 : // it has been set up.
89 : void ClearThread(const ExecutionAccess& lock);
90 :
91 : #define INTERRUPT_LIST(V) \
92 : V(DEBUGBREAK, DebugBreak, 0) \
93 : V(TERMINATE_EXECUTION, TerminateExecution, 1) \
94 : V(GC_REQUEST, GC, 2) \
95 : V(INSTALL_CODE, InstallCode, 3) \
96 : V(API_INTERRUPT, ApiInterrupt, 4) \
97 : V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites, 5)
98 :
99 : #define V(NAME, Name, id) \
100 : inline bool Check##Name() { return CheckInterrupt(NAME); } \
101 : inline bool CheckAndClear##Name() { return CheckAndClearInterrupt(NAME); } \
102 : inline void Request##Name() { RequestInterrupt(NAME); } \
103 : inline void Clear##Name() { ClearInterrupt(NAME); }
104 86873 : INTERRUPT_LIST(V)
105 : #undef V
106 :
107 : // Flag used to set the interrupt causes.
108 : enum InterruptFlag {
109 : #define V(NAME, Name, id) NAME = (1 << id),
110 : INTERRUPT_LIST(V)
111 : #undef V
112 : #define V(NAME, Name, id) NAME |
113 : ALL_INTERRUPTS = INTERRUPT_LIST(V) 0
114 : #undef V
115 : };
116 :
117 : uintptr_t climit() { return thread_local_.climit(); }
118 : uintptr_t jslimit() { return thread_local_.jslimit(); }
119 : // This provides an asynchronous read of the stack limits for the current
120 : // thread. There are no locks protecting this, but it is assumed that you
121 : // have the global V8 lock if you are using multiple V8 threads.
122 : uintptr_t real_climit() {
123 : return thread_local_.real_climit_;
124 : }
125 : uintptr_t real_jslimit() {
126 : return thread_local_.real_jslimit_;
127 : }
128 : Address address_of_jslimit() {
129 : return reinterpret_cast<Address>(&thread_local_.jslimit_);
130 : }
131 : Address address_of_real_jslimit() {
132 : return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
133 : }
134 :
135 : // If the stack guard is triggered, but it is not an actual
136 : // stack overflow, then handle the interruption accordingly.
137 : Object* HandleInterrupts();
138 : void HandleGCInterrupt();
139 :
140 : private:
141 : StackGuard();
142 :
143 : bool CheckInterrupt(InterruptFlag flag);
144 : void RequestInterrupt(InterruptFlag flag);
145 : void ClearInterrupt(InterruptFlag flag);
146 : bool CheckAndClearInterrupt(InterruptFlag flag);
147 :
148 : // You should hold the ExecutionAccess lock when calling this method.
149 : bool has_pending_interrupts(const ExecutionAccess& lock) {
150 : return thread_local_.interrupt_flags_ != 0;
151 : }
152 :
153 : // You should hold the ExecutionAccess lock when calling this method.
154 : inline void set_interrupt_limits(const ExecutionAccess& lock);
155 :
156 : // Reset limits to actual values. For example after handling interrupt.
157 : // You should hold the ExecutionAccess lock when calling this method.
158 : inline void reset_limits(const ExecutionAccess& lock);
159 :
160 : // Enable or disable interrupts.
161 : void EnableInterrupts();
162 : void DisableInterrupts();
163 :
164 : #if V8_TARGET_ARCH_64_BIT
165 : static const uintptr_t kInterruptLimit = V8_UINT64_C(0xfffffffffffffffe);
166 : static const uintptr_t kIllegalLimit = V8_UINT64_C(0xfffffffffffffff8);
167 : #else
168 : static const uintptr_t kInterruptLimit = 0xfffffffe;
169 : static const uintptr_t kIllegalLimit = 0xfffffff8;
170 : #endif
171 :
172 : void PushPostponeInterruptsScope(PostponeInterruptsScope* scope);
173 : void PopPostponeInterruptsScope();
174 :
175 : class ThreadLocal final {
176 : public:
177 79162 : ThreadLocal() { Clear(); }
178 : // You should hold the ExecutionAccess lock when you call Initialize or
179 : // Clear.
180 : void Clear();
181 :
182 : // Returns true if the heap's stack limits should be set, false if not.
183 : bool Initialize(Isolate* isolate);
184 :
185 : // The stack limit is split into a JavaScript and a C++ stack limit. These
186 : // two are the same except when running on a simulator where the C++ and
187 : // JavaScript stacks are separate. Each of the two stack limits have two
188 : // values. The one eith the real_ prefix is the actual stack limit
189 : // set for the VM. The one without the real_ prefix has the same value as
190 : // the actual stack limit except when there is an interruption (e.g. debug
191 : // break or preemption) in which case it is lowered to make stack checks
192 : // fail. Both the generated code and the runtime system check against the
193 : // one without the real_ prefix.
194 : uintptr_t real_jslimit_; // Actual JavaScript stack limit set for the VM.
195 : uintptr_t real_climit_; // Actual C++ stack limit set for the VM.
196 :
197 : // jslimit_ and climit_ can be read without any lock.
198 : // Writing requires the ExecutionAccess lock.
199 : base::AtomicWord jslimit_;
200 : base::AtomicWord climit_;
201 :
202 : uintptr_t jslimit() {
203 4369293 : return bit_cast<uintptr_t>(base::Relaxed_Load(&jslimit_));
204 : }
205 : void set_jslimit(uintptr_t limit) {
206 : return base::Relaxed_Store(&jslimit_,
207 4288337 : static_cast<base::AtomicWord>(limit));
208 : }
209 : uintptr_t climit() {
210 50373179 : return bit_cast<uintptr_t>(base::Relaxed_Load(&climit_));
211 : }
212 : void set_climit(uintptr_t limit) {
213 : return base::Relaxed_Store(&climit_,
214 4288337 : static_cast<base::AtomicWord>(limit));
215 : }
216 :
217 : PostponeInterruptsScope* postpone_interrupts_;
218 : int interrupt_flags_;
219 : };
220 :
221 : // TODO(isolates): Technically this could be calculated directly from a
222 : // pointer to StackGuard.
223 : Isolate* isolate_;
224 : ThreadLocal thread_local_;
225 :
226 : friend class Isolate;
227 : friend class StackLimitCheck;
228 : friend class PostponeInterruptsScope;
229 :
230 : DISALLOW_COPY_AND_ASSIGN(StackGuard);
231 : };
232 :
233 : } // namespace internal
234 : } // namespace v8
235 :
236 : #endif // V8_EXECUTION_H_
|