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