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/base/atomicops.h"
9 : #include "src/globals.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : class MicrotaskQueue;
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 : enum class Target { kCallable, kRunMicrotasks };
24 :
25 : // Call a function, the caller supplies a receiver and an array
26 : // of arguments.
27 : //
28 : // When the function called is not in strict mode, receiver is
29 : // converted to an object.
30 : //
31 : V8_EXPORT_PRIVATE V8_WARN_UNUSED_RESULT static MaybeHandle<Object> Call(
32 : Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
33 : int argc, Handle<Object> argv[]);
34 :
35 : // Construct object from function, the caller supplies an array of
36 : // arguments.
37 : V8_WARN_UNUSED_RESULT static MaybeHandle<Object> New(
38 : Isolate* isolate, Handle<Object> constructor, int argc,
39 : Handle<Object> argv[]);
40 : V8_WARN_UNUSED_RESULT static MaybeHandle<Object> New(
41 : Isolate* isolate, Handle<Object> constructor, Handle<Object> new_target,
42 : int argc, Handle<Object> argv[]);
43 :
44 : // Call a function, just like Call(), but handle don't report exceptions
45 : // externally.
46 : // The return value is either the result of calling the function (if no
47 : // exception occurred), or an empty handle.
48 : // If message_handling is MessageHandling::kReport, exceptions (except for
49 : // termination exceptions) will be stored in exception_out (if not a
50 : // nullptr).
51 : static MaybeHandle<Object> TryCall(Isolate* isolate, Handle<Object> callable,
52 : Handle<Object> receiver, int argc,
53 : Handle<Object> argv[],
54 : MessageHandling message_handling,
55 : MaybeHandle<Object>* exception_out);
56 : // Convenience method for performing RunMicrotasks
57 : static MaybeHandle<Object> TryRunMicrotasks(
58 : Isolate* isolate, MicrotaskQueue* microtask_queue,
59 : MaybeHandle<Object>* exception_out);
60 : };
61 :
62 :
63 : class ExecutionAccess;
64 : class InterruptsScope;
65 :
66 : // StackGuard contains the handling of the limits that are used to limit the
67 : // number of nested invocations of JavaScript and the stack size used in each
68 : // invocation.
69 : class V8_EXPORT_PRIVATE StackGuard final {
70 : public:
71 61534 : explicit StackGuard(Isolate* isolate) : isolate_(isolate) {}
72 :
73 : // Pass the address beyond which the stack should not grow. The stack
74 : // is assumed to grow downwards.
75 : void SetStackLimit(uintptr_t limit);
76 :
77 : // The simulator uses a separate JS stack. Limits on the JS stack might have
78 : // to be adjusted in order to reflect overflows of the C stack, because we
79 : // cannot rely on the interleaving of frames on the simulator.
80 : void AdjustStackLimitForSimulator();
81 :
82 : // Threading support.
83 : char* ArchiveStackGuard(char* to);
84 : char* RestoreStackGuard(char* from);
85 : static int ArchiveSpacePerThread() { return sizeof(ThreadLocal); }
86 : void FreeThreadResources();
87 : // Sets up the default stack guard for this thread if it has not
88 : // already been set up.
89 : void InitThread(const ExecutionAccess& lock);
90 : // Clears the stack guard for this thread so it does not look as if
91 : // it has been set up.
92 : void ClearThread(const ExecutionAccess& lock);
93 :
94 : #define INTERRUPT_LIST(V) \
95 : V(TERMINATE_EXECUTION, TerminateExecution, 0) \
96 : V(GC_REQUEST, GC, 1) \
97 : V(INSTALL_CODE, InstallCode, 2) \
98 : V(API_INTERRUPT, ApiInterrupt, 3) \
99 : V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites, 4) \
100 : V(GROW_SHARED_MEMORY, GrowSharedMemory, 5)
101 :
102 : #define V(NAME, Name, id) \
103 : inline bool Check##Name() { return CheckInterrupt(NAME); } \
104 : inline bool CheckAndClear##Name() { return CheckAndClearInterrupt(NAME); } \
105 : inline void Request##Name() { RequestInterrupt(NAME); } \
106 : inline void Clear##Name() { ClearInterrupt(NAME); }
107 1092062 : INTERRUPT_LIST(V)
108 : #undef V
109 :
110 : // Flag used to set the interrupt causes.
111 : enum InterruptFlag {
112 : #define V(NAME, Name, id) NAME = (1 << id),
113 : INTERRUPT_LIST(V)
114 : #undef V
115 : #define V(NAME, Name, id) NAME |
116 : ALL_INTERRUPTS = INTERRUPT_LIST(V) 0
117 : #undef V
118 : };
119 :
120 : uintptr_t climit() { return thread_local_.climit(); }
121 : uintptr_t jslimit() { return thread_local_.jslimit(); }
122 : // This provides an asynchronous read of the stack limits for the current
123 : // thread. There are no locks protecting this, but it is assumed that you
124 : // have the global V8 lock if you are using multiple V8 threads.
125 : uintptr_t real_climit() {
126 : return thread_local_.real_climit_;
127 : }
128 : uintptr_t real_jslimit() {
129 : return thread_local_.real_jslimit_;
130 : }
131 : Address address_of_jslimit() {
132 2684890 : return reinterpret_cast<Address>(&thread_local_.jslimit_);
133 : }
134 : Address address_of_real_jslimit() {
135 1291574 : return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
136 : }
137 :
138 : // If the stack guard is triggered, but it is not an actual
139 : // stack overflow, then handle the interruption accordingly.
140 : Object HandleInterrupts();
141 :
142 : private:
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 = uintptr_t{0xfffffffffffffffe};
166 : static const uintptr_t kIllegalLimit = uintptr_t{0xfffffffffffffff8};
167 : #else
168 : static const uintptr_t kInterruptLimit = 0xfffffffe;
169 : static const uintptr_t kIllegalLimit = 0xfffffff8;
170 : #endif
171 :
172 : void PushInterruptsScope(InterruptsScope* scope);
173 : void PopInterruptsScope();
174 :
175 : class ThreadLocal final {
176 : public:
177 93971 : 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 16165898 : return bit_cast<uintptr_t>(base::Relaxed_Load(&jslimit_));
204 : }
205 : void set_jslimit(uintptr_t limit) {
206 16069820 : return base::Relaxed_Store(&jslimit_,
207 : static_cast<base::AtomicWord>(limit));
208 : }
209 : uintptr_t climit() {
210 52176154 : return bit_cast<uintptr_t>(base::Relaxed_Load(&climit_));
211 : }
212 : void set_climit(uintptr_t limit) {
213 16069820 : return base::Relaxed_Store(&climit_,
214 : static_cast<base::AtomicWord>(limit));
215 : }
216 :
217 : InterruptsScope* interrupt_scopes_;
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 InterruptsScope;
229 :
230 : DISALLOW_COPY_AND_ASSIGN(StackGuard);
231 : };
232 :
233 : } // namespace internal
234 : } // namespace v8
235 :
236 : #endif // V8_EXECUTION_H_
|