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 : #include "src/execution.h"
6 :
7 : #include "src/api-inl.h"
8 : #include "src/bootstrapper.h"
9 : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
10 : #include "src/debug/debug.h"
11 : #include "src/isolate-inl.h"
12 : #include "src/runtime-profiler.h"
13 : #include "src/vm-state-inl.h"
14 :
15 : #define TRACE_INTERRUPT(...) \
16 : do { \
17 : if (FLAG_trace_interrupts) { \
18 : if (any_interrupt_handled) PrintF(", "); \
19 : PrintF(__VA_ARGS__); \
20 : any_interrupt_handled = true; \
21 : } \
22 : } while (false)
23 :
24 : namespace v8 {
25 : namespace internal {
26 :
27 1132944 : void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
28 : DCHECK_NOT_NULL(isolate_);
29 : thread_local_.set_jslimit(kInterruptLimit);
30 : thread_local_.set_climit(kInterruptLimit);
31 2265888 : isolate_->heap()->SetStackLimits();
32 1132944 : }
33 :
34 14768265 : void StackGuard::reset_limits(const ExecutionAccess& lock) {
35 : DCHECK_NOT_NULL(isolate_);
36 14768265 : thread_local_.set_jslimit(thread_local_.real_jslimit_);
37 14768265 : thread_local_.set_climit(thread_local_.real_climit_);
38 29536530 : isolate_->heap()->SetStackLimits();
39 14768251 : }
40 :
41 : namespace {
42 :
43 17954371 : Handle<Object> NormalizeReceiver(Isolate* isolate, Handle<Object> receiver) {
44 : // Convert calls on global objects to be calls on the global
45 : // receiver instead to avoid having a 'this' pointer which refers
46 : // directly to a global object.
47 17954371 : if (receiver->IsJSGlobalObject()) {
48 : return handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(),
49 37294 : isolate);
50 : }
51 17917077 : return receiver;
52 : }
53 :
54 : struct InvokeParams {
55 : static InvokeParams SetUpForNew(Isolate* isolate, Handle<Object> constructor,
56 : Handle<Object> new_target, int argc,
57 : Handle<Object>* argv);
58 :
59 : static InvokeParams SetUpForCall(Isolate* isolate, Handle<Object> callable,
60 : Handle<Object> receiver, int argc,
61 : Handle<Object>* argv);
62 :
63 : static InvokeParams SetUpForTryCall(
64 : Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
65 : int argc, Handle<Object>* argv,
66 : Execution::MessageHandling message_handling,
67 : MaybeHandle<Object>* exception_out);
68 :
69 : static InvokeParams SetUpForRunMicrotasks(Isolate* isolate,
70 : MicrotaskQueue* microtask_queue,
71 : MaybeHandle<Object>* exception_out);
72 :
73 : Handle<Object> target;
74 : Handle<Object> receiver;
75 : int argc;
76 : Handle<Object>* argv;
77 : Handle<Object> new_target;
78 :
79 : MicrotaskQueue* microtask_queue;
80 :
81 : Execution::MessageHandling message_handling;
82 : MaybeHandle<Object>* exception_out;
83 :
84 : bool is_construct;
85 : Execution::Target execution_target;
86 : };
87 :
88 : // static
89 : InvokeParams InvokeParams::SetUpForNew(Isolate* isolate,
90 : Handle<Object> constructor,
91 : Handle<Object> new_target, int argc,
92 : Handle<Object>* argv) {
93 : InvokeParams params;
94 1870 : params.target = constructor;
95 1870 : params.receiver = isolate->factory()->undefined_value();
96 1870 : params.argc = argc;
97 1870 : params.argv = argv;
98 1870 : params.new_target = new_target;
99 1870 : params.microtask_queue = nullptr;
100 1870 : params.message_handling = Execution::MessageHandling::kReport;
101 1870 : params.exception_out = nullptr;
102 1870 : params.is_construct = true;
103 1870 : params.execution_target = Execution::Target::kCallable;
104 : return params;
105 : }
106 :
107 : // static
108 : InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
109 : Handle<Object> callable,
110 : Handle<Object> receiver, int argc,
111 : Handle<Object>* argv) {
112 : InvokeParams params;
113 17942450 : params.target = callable;
114 17942450 : params.receiver = NormalizeReceiver(isolate, receiver);
115 17942454 : params.argc = argc;
116 17942454 : params.argv = argv;
117 17942454 : params.new_target = isolate->factory()->undefined_value();
118 17942454 : params.microtask_queue = nullptr;
119 17942454 : params.message_handling = Execution::MessageHandling::kReport;
120 17942454 : params.exception_out = nullptr;
121 17942454 : params.is_construct = false;
122 17942454 : params.execution_target = Execution::Target::kCallable;
123 : return params;
124 : }
125 :
126 : // static
127 : InvokeParams InvokeParams::SetUpForTryCall(
128 : Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
129 : int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
130 : MaybeHandle<Object>* exception_out) {
131 : InvokeParams params;
132 11908 : params.target = callable;
133 11908 : params.receiver = NormalizeReceiver(isolate, receiver);
134 11919 : params.argc = argc;
135 11919 : params.argv = argv;
136 11919 : params.new_target = isolate->factory()->undefined_value();
137 11919 : params.microtask_queue = nullptr;
138 11919 : params.message_handling = message_handling;
139 11919 : params.exception_out = exception_out;
140 11919 : params.is_construct = false;
141 11919 : params.execution_target = Execution::Target::kCallable;
142 : return params;
143 : }
144 :
145 : // static
146 : InvokeParams InvokeParams::SetUpForRunMicrotasks(
147 : Isolate* isolate, MicrotaskQueue* microtask_queue,
148 : MaybeHandle<Object>* exception_out) {
149 : auto undefined = isolate->factory()->undefined_value();
150 : InvokeParams params;
151 37785 : params.target = undefined;
152 37785 : params.receiver = undefined;
153 37785 : params.argc = 0;
154 37785 : params.argv = nullptr;
155 37785 : params.new_target = undefined;
156 37785 : params.microtask_queue = microtask_queue;
157 37785 : params.message_handling = Execution::MessageHandling::kReport;
158 37785 : params.exception_out = exception_out;
159 37785 : params.is_construct = false;
160 37785 : params.execution_target = Execution::Target::kRunMicrotasks;
161 : return params;
162 : }
163 :
164 17981340 : Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
165 : bool is_construct) {
166 17981340 : if (is_construct) {
167 : DCHECK_EQ(Execution::Target::kCallable, execution_target);
168 1097 : return BUILTIN_CODE(isolate, JSConstructEntry);
169 17980243 : } else if (execution_target == Execution::Target::kCallable) {
170 : DCHECK(!is_construct);
171 17942458 : return BUILTIN_CODE(isolate, JSEntry);
172 37785 : } else if (execution_target == Execution::Target::kRunMicrotasks) {
173 : DCHECK(!is_construct);
174 37785 : return BUILTIN_CODE(isolate, JSRunMicrotasksEntry);
175 : }
176 0 : UNREACHABLE();
177 : }
178 :
179 17994011 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
180 : const InvokeParams& params) {
181 17994011 : RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kInvoke);
182 : DCHECK(!params.receiver->IsJSGlobalObject());
183 : DCHECK_LE(params.argc, FixedArray::kMaxLength);
184 :
185 : #ifdef USE_SIMULATOR
186 : // Simulators use separate stacks for C++ and JS. JS stack overflow checks
187 : // are performed whenever a JS function is called. However, it can be the case
188 : // that the C++ stack grows faster than the JS stack, resulting in an overflow
189 : // there. Add a check here to make that less likely.
190 : StackLimitCheck check(isolate);
191 : if (check.HasOverflowed()) {
192 : isolate->StackOverflow();
193 : if (params.message_handling == Execution::MessageHandling::kReport) {
194 : isolate->ReportPendingMessages();
195 : }
196 : return MaybeHandle<Object>();
197 : }
198 : #endif
199 :
200 : // api callbacks can be called directly, unless we want to take the detour
201 : // through JS to set up a frame for break-at-entry.
202 17994014 : if (params.target->IsJSFunction()) {
203 : Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
204 53493903 : if ((!params.is_construct || function->IsConstructor()) &&
205 53504938 : function->shared()->IsApiFunction() &&
206 17843591 : !function->shared()->BreakAtEntry()) {
207 12670 : SaveAndSwitchContext save(isolate, function->context());
208 : DCHECK(function->context()->global_object()->IsJSGlobalObject());
209 :
210 12668 : Handle<Object> receiver = params.is_construct
211 : ? isolate->factory()->the_hole_value()
212 24563 : : params.receiver;
213 : auto value = Builtins::InvokeApiFunction(
214 12668 : isolate, params.is_construct, function, receiver, params.argc,
215 25336 : params.argv, Handle<HeapObject>::cast(params.new_target));
216 : bool has_exception = value.is_null();
217 : DCHECK(has_exception == isolate->has_pending_exception());
218 12669 : if (has_exception) {
219 214 : if (params.message_handling == Execution::MessageHandling::kReport) {
220 214 : isolate->ReportPendingMessages();
221 : }
222 214 : return MaybeHandle<Object>();
223 : } else {
224 : isolate->clear_pending_message();
225 : }
226 12455 : return value;
227 : }
228 : }
229 :
230 : // Entering JavaScript.
231 : VMState<JS> state(isolate);
232 17981348 : CHECK(AllowJavascriptExecution::IsAllowed(isolate));
233 17981345 : if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
234 5 : isolate->ThrowIllegalOperation();
235 5 : if (params.message_handling == Execution::MessageHandling::kReport) {
236 5 : isolate->ReportPendingMessages();
237 : }
238 7 : return MaybeHandle<Object>();
239 : }
240 17981340 : if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
241 5 : V8::GetCurrentPlatform()->DumpWithoutCrashing();
242 5 : return isolate->factory()->undefined_value();
243 : }
244 :
245 : // Placeholder for return value.
246 : Object value;
247 :
248 : Handle<Code> code =
249 17981335 : JSEntry(isolate, params.execution_target, params.is_construct);
250 : {
251 : // Save and restore context around invocation and block the
252 : // allocation of handles without explicit handle scopes.
253 35962687 : SaveContext save(isolate);
254 : SealHandleScope shs(isolate);
255 :
256 17981336 : if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
257 :
258 17981336 : if (params.execution_target == Execution::Target::kCallable) {
259 : // clang-format off
260 : // {new_target}, {target}, {receiver}, return value: tagged pointers
261 : // {argv}: pointer to array of tagged pointers
262 : using JSEntryFunction = GeneratedCode<Address(
263 : Address root_register_value, Address new_target, Address target,
264 : Address receiver, intptr_t argc, Address** argv)>;
265 : // clang-format on
266 : JSEntryFunction stub_entry =
267 35887100 : JSEntryFunction::FromAddress(isolate, code->InstructionStart());
268 :
269 : Address orig_func = params.new_target->ptr();
270 : Address func = params.target->ptr();
271 : Address recv = params.receiver->ptr();
272 17943549 : Address** argv = reinterpret_cast<Address**>(params.argv);
273 17943549 : RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
274 : value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
275 17943551 : orig_func, func, recv, params.argc, argv));
276 : } else {
277 : DCHECK_EQ(Execution::Target::kRunMicrotasks, params.execution_target);
278 :
279 : // clang-format off
280 : // return value: tagged pointers
281 : // {microtask_queue}: pointer to a C++ object
282 : using JSEntryFunction = GeneratedCode<Address(
283 : Address root_register_value, MicrotaskQueue* microtask_queue)>;
284 : // clang-format on
285 : JSEntryFunction stub_entry =
286 75570 : JSEntryFunction::FromAddress(isolate, code->InstructionStart());
287 :
288 37785 : RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
289 : value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
290 37785 : params.microtask_queue));
291 : }
292 : }
293 :
294 : #ifdef VERIFY_HEAP
295 : if (FLAG_verify_heap) {
296 : value->ObjectVerify(isolate);
297 : }
298 : #endif
299 :
300 : // Update the pending exception flag and return the value.
301 : bool has_exception = value->IsException(isolate);
302 : DCHECK(has_exception == isolate->has_pending_exception());
303 17981351 : if (has_exception) {
304 118860 : if (params.message_handling == Execution::MessageHandling::kReport) {
305 118855 : isolate->ReportPendingMessages();
306 : }
307 118860 : return MaybeHandle<Object>();
308 : } else {
309 : isolate->clear_pending_message();
310 : }
311 :
312 17862487 : return Handle<Object>(value, isolate);
313 : }
314 :
315 49703 : MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
316 : const InvokeParams& params) {
317 : bool is_termination = false;
318 : MaybeHandle<Object> maybe_result;
319 49703 : if (params.exception_out != nullptr) {
320 38039 : *params.exception_out = MaybeHandle<Object>();
321 : }
322 : DCHECK_IMPLIES(
323 : params.message_handling == Execution::MessageHandling::kKeepPending,
324 : params.exception_out == nullptr);
325 : // Enter a try-block while executing the JavaScript code. To avoid
326 : // duplicate error printing it must be non-verbose. Also, to avoid
327 : // creating message objects during stack overflow we shouldn't
328 : // capture messages.
329 : {
330 99404 : v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
331 49699 : catcher.SetVerbose(false);
332 49700 : catcher.SetCaptureMessage(false);
333 :
334 49699 : maybe_result = Invoke(isolate, params);
335 :
336 49701 : if (maybe_result.is_null()) {
337 : DCHECK(isolate->has_pending_exception());
338 2070 : if (isolate->pending_exception() ==
339 : ReadOnlyRoots(isolate).termination_exception()) {
340 : is_termination = true;
341 : } else {
342 2045 : if (params.exception_out != nullptr) {
343 : DCHECK(catcher.HasCaught());
344 : DCHECK(isolate->external_caught_exception());
345 120 : *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
346 : }
347 : }
348 2070 : if (params.message_handling == Execution::MessageHandling::kReport) {
349 2065 : isolate->OptionalRescheduleException(true);
350 : }
351 : }
352 : }
353 :
354 : // Re-request terminate execution interrupt to trigger later.
355 49700 : if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
356 :
357 49700 : return maybe_result;
358 : }
359 :
360 : } // namespace
361 :
362 : // static
363 17942450 : MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
364 : Handle<Object> receiver, int argc,
365 : Handle<Object> argv[]) {
366 17942460 : return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
367 35884914 : argc, argv));
368 : }
369 :
370 : // static
371 773 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
372 : int argc, Handle<Object> argv[]) {
373 773 : return New(isolate, constructor, constructor, argc, argv);
374 : }
375 :
376 : // static
377 1870 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
378 : Handle<Object> new_target, int argc,
379 : Handle<Object> argv[]) {
380 1870 : return Invoke(isolate, InvokeParams::SetUpForNew(isolate, constructor,
381 3740 : new_target, argc, argv));
382 : }
383 :
384 : // static
385 11908 : MaybeHandle<Object> Execution::TryCall(Isolate* isolate,
386 : Handle<Object> callable,
387 : Handle<Object> receiver, int argc,
388 : Handle<Object> argv[],
389 : MessageHandling message_handling,
390 : MaybeHandle<Object>* exception_out) {
391 : return InvokeWithTryCatch(
392 : isolate,
393 11915 : InvokeParams::SetUpForTryCall(isolate, callable, receiver, argc, argv,
394 23834 : message_handling, exception_out));
395 : }
396 :
397 : // static
398 37785 : MaybeHandle<Object> Execution::TryRunMicrotasks(
399 : Isolate* isolate, MicrotaskQueue* microtask_queue,
400 : MaybeHandle<Object>* exception_out) {
401 : return InvokeWithTryCatch(
402 37785 : isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
403 75570 : exception_out));
404 : }
405 :
406 1851 : void StackGuard::SetStackLimit(uintptr_t limit) {
407 1851 : ExecutionAccess access(isolate_);
408 : // If the current limits are special (e.g. due to a pending interrupt) then
409 : // leave them alone.
410 : uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
411 1851 : if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
412 : thread_local_.set_jslimit(jslimit);
413 : }
414 1851 : if (thread_local_.climit() == thread_local_.real_climit_) {
415 : thread_local_.set_climit(limit);
416 : }
417 1851 : thread_local_.real_climit_ = limit;
418 1851 : thread_local_.real_jslimit_ = jslimit;
419 1851 : }
420 :
421 :
422 0 : void StackGuard::AdjustStackLimitForSimulator() {
423 0 : ExecutionAccess access(isolate_);
424 0 : uintptr_t climit = thread_local_.real_climit_;
425 : // If the current limits are special (e.g. due to a pending interrupt) then
426 : // leave them alone.
427 : uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
428 0 : if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
429 : thread_local_.set_jslimit(jslimit);
430 0 : isolate_->heap()->SetStackLimits();
431 : }
432 0 : }
433 :
434 :
435 0 : void StackGuard::EnableInterrupts() {
436 0 : ExecutionAccess access(isolate_);
437 0 : if (has_pending_interrupts(access)) {
438 0 : set_interrupt_limits(access);
439 : }
440 0 : }
441 :
442 :
443 0 : void StackGuard::DisableInterrupts() {
444 0 : ExecutionAccess access(isolate_);
445 0 : reset_limits(access);
446 0 : }
447 :
448 4402633 : void StackGuard::PushInterruptsScope(InterruptsScope* scope) {
449 4402633 : ExecutionAccess access(isolate_);
450 : DCHECK_NE(scope->mode_, InterruptsScope::kNoop);
451 4402653 : if (scope->mode_ == InterruptsScope::kPostponeInterrupts) {
452 : // Intercept already requested interrupts.
453 4371313 : int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
454 4371313 : scope->intercepted_flags_ = intercepted;
455 4371313 : thread_local_.interrupt_flags_ &= ~intercepted;
456 : } else {
457 : DCHECK_EQ(scope->mode_, InterruptsScope::kRunInterrupts);
458 : // Restore postponed interrupts.
459 : int restored_flags = 0;
460 47650 : for (InterruptsScope* current = thread_local_.interrupt_scopes_;
461 47650 : current != nullptr; current = current->prev_) {
462 16310 : restored_flags |= (current->intercepted_flags_ & scope->intercept_mask_);
463 16310 : current->intercepted_flags_ &= ~scope->intercept_mask_;
464 : }
465 31340 : thread_local_.interrupt_flags_ |= restored_flags;
466 : }
467 4402653 : if (!has_pending_interrupts(access)) reset_limits(access);
468 : // Add scope to the chain.
469 4402639 : scope->prev_ = thread_local_.interrupt_scopes_;
470 4402639 : thread_local_.interrupt_scopes_ = scope;
471 4402654 : }
472 :
473 4402639 : void StackGuard::PopInterruptsScope() {
474 4402639 : ExecutionAccess access(isolate_);
475 4402663 : InterruptsScope* top = thread_local_.interrupt_scopes_;
476 : DCHECK_NE(top->mode_, InterruptsScope::kNoop);
477 4402663 : if (top->mode_ == InterruptsScope::kPostponeInterrupts) {
478 : // Make intercepted interrupts active.
479 : DCHECK_EQ(thread_local_.interrupt_flags_ & top->intercept_mask_, 0);
480 4371323 : thread_local_.interrupt_flags_ |= top->intercepted_flags_;
481 : } else {
482 : DCHECK_EQ(top->mode_, InterruptsScope::kRunInterrupts);
483 : // Postpone existing interupts if needed.
484 31340 : if (top->prev_) {
485 196768 : for (int interrupt = 1; interrupt < ALL_INTERRUPTS;
486 : interrupt = interrupt << 1) {
487 90816 : InterruptFlag flag = static_cast<InterruptFlag>(interrupt);
488 90852 : if ((thread_local_.interrupt_flags_ & flag) &&
489 36 : top->prev_->Intercept(flag)) {
490 21 : thread_local_.interrupt_flags_ &= ~flag;
491 : }
492 : }
493 : }
494 : }
495 4402663 : if (has_pending_interrupts(access)) set_interrupt_limits(access);
496 : // Remove scope from chain.
497 4402663 : thread_local_.interrupt_scopes_ = top->prev_;
498 4402663 : }
499 :
500 :
501 3 : bool StackGuard::CheckInterrupt(InterruptFlag flag) {
502 3 : ExecutionAccess access(isolate_);
503 6 : return thread_local_.interrupt_flags_ & flag;
504 : }
505 :
506 :
507 1067165 : void StackGuard::RequestInterrupt(InterruptFlag flag) {
508 1067165 : ExecutionAccess access(isolate_);
509 : // Check the chain of InterruptsScope for interception.
510 1140479 : if (thread_local_.interrupt_scopes_ &&
511 73314 : thread_local_.interrupt_scopes_->Intercept(flag)) {
512 : return;
513 : }
514 :
515 : // Not intercepted. Set as active interrupt flag.
516 994281 : thread_local_.interrupt_flags_ |= flag;
517 994281 : set_interrupt_limits(access);
518 :
519 : // If this isolate is waiting in a futex, notify it to wake up.
520 1988562 : isolate_->futex_wait_list_node()->NotifyWake();
521 : }
522 :
523 :
524 24894 : void StackGuard::ClearInterrupt(InterruptFlag flag) {
525 24894 : ExecutionAccess access(isolate_);
526 : // Clear the interrupt flag from the chain of InterruptsScope.
527 47511 : for (InterruptsScope* current = thread_local_.interrupt_scopes_;
528 47511 : current != nullptr; current = current->prev_) {
529 22617 : current->intercepted_flags_ &= ~flag;
530 : }
531 :
532 : // Clear the interrupt flag from the active interrupt flags.
533 24894 : thread_local_.interrupt_flags_ &= ~flag;
534 24894 : if (!has_pending_interrupts(access)) reset_limits(access);
535 24894 : }
536 :
537 :
538 10387632 : bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
539 10387632 : ExecutionAccess access(isolate_);
540 10387632 : bool result = (thread_local_.interrupt_flags_ & flag);
541 10387632 : thread_local_.interrupt_flags_ &= ~flag;
542 10387632 : if (!has_pending_interrupts(access)) reset_limits(access);
543 10387632 : return result;
544 : }
545 :
546 :
547 32437 : char* StackGuard::ArchiveStackGuard(char* to) {
548 32437 : ExecutionAccess access(isolate_);
549 32437 : MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
550 : ThreadLocal blank;
551 :
552 : // Set the stack limits using the old thread_local_.
553 : // TODO(isolates): This was the old semantics of constructing a ThreadLocal
554 : // (as the ctor called SetStackLimits, which looked at the
555 : // current thread_local_ from StackGuard)-- but is this
556 : // really what was intended?
557 64874 : isolate_->heap()->SetStackLimits();
558 32437 : thread_local_ = blank;
559 :
560 64874 : return to + sizeof(ThreadLocal);
561 : }
562 :
563 :
564 32437 : char* StackGuard::RestoreStackGuard(char* from) {
565 32437 : ExecutionAccess access(isolate_);
566 32437 : MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
567 64874 : isolate_->heap()->SetStackLimits();
568 64874 : return from + sizeof(ThreadLocal);
569 : }
570 :
571 :
572 5918 : void StackGuard::FreeThreadResources() {
573 : Isolate::PerIsolateThreadData* per_thread =
574 5918 : isolate_->FindOrAllocatePerThreadDataForThisThread();
575 5918 : per_thread->set_stack_limit(thread_local_.real_climit_);
576 5918 : }
577 :
578 :
579 99889 : void StackGuard::ThreadLocal::Clear() {
580 99889 : real_jslimit_ = kIllegalLimit;
581 : set_jslimit(kIllegalLimit);
582 99889 : real_climit_ = kIllegalLimit;
583 : set_climit(kIllegalLimit);
584 99889 : interrupt_scopes_ = nullptr;
585 99889 : interrupt_flags_ = 0;
586 99889 : }
587 :
588 :
589 73369 : bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
590 : bool should_set_stack_limits = false;
591 73369 : if (real_climit_ == kIllegalLimit) {
592 68722 : const uintptr_t kLimitSize = FLAG_stack_size * KB;
593 : DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
594 68722 : uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
595 68722 : real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
596 : set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
597 68722 : real_climit_ = limit;
598 : set_climit(limit);
599 : should_set_stack_limits = true;
600 : }
601 73369 : interrupt_scopes_ = nullptr;
602 73369 : interrupt_flags_ = 0;
603 73369 : return should_set_stack_limits;
604 : }
605 :
606 :
607 5918 : void StackGuard::ClearThread(const ExecutionAccess& lock) {
608 5918 : thread_local_.Clear();
609 11836 : isolate_->heap()->SetStackLimits();
610 5918 : }
611 :
612 :
613 73369 : void StackGuard::InitThread(const ExecutionAccess& lock) {
614 142091 : if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
615 : Isolate::PerIsolateThreadData* per_thread =
616 73370 : isolate_->FindOrAllocatePerThreadDataForThisThread();
617 : uintptr_t stored_limit = per_thread->stack_limit();
618 : // You should hold the ExecutionAccess lock when you call this.
619 73368 : if (stored_limit != 0) {
620 190 : SetStackLimit(stored_limit);
621 : }
622 73368 : }
623 :
624 :
625 : // --- C a l l s t o n a t i v e s ---
626 :
627 1731910 : Object StackGuard::HandleInterrupts() {
628 : if (FLAG_verify_predictable) {
629 : // Advance synthetic time by making a time request.
630 : isolate_->heap()->MonotonicallyIncreasingTimeInMs();
631 : }
632 :
633 : bool any_interrupt_handled = false;
634 1731910 : if (FLAG_trace_interrupts) {
635 0 : PrintF("[Handling interrupts: ");
636 : }
637 :
638 1731910 : if (CheckAndClearInterrupt(GC_REQUEST)) {
639 12026 : TRACE_INTERRUPT("GC_REQUEST");
640 24052 : isolate_->heap()->HandleGCRequest();
641 : }
642 :
643 1731910 : if (CheckAndClearInterrupt(GROW_SHARED_MEMORY)) {
644 136 : TRACE_INTERRUPT("GROW_SHARED_MEMORY");
645 136 : isolate_->wasm_engine()->memory_tracker()->UpdateSharedMemoryInstances(
646 136 : isolate_);
647 : }
648 :
649 1731910 : if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
650 1276 : TRACE_INTERRUPT("TERMINATE_EXECUTION");
651 1276 : return isolate_->TerminateExecution();
652 : }
653 :
654 1730634 : if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
655 24 : TRACE_INTERRUPT("DEOPT_MARKED_ALLOCATION_SITES");
656 48 : isolate_->heap()->DeoptMarkedAllocationSites();
657 : }
658 :
659 1730634 : if (CheckAndClearInterrupt(INSTALL_CODE)) {
660 6319 : TRACE_INTERRUPT("INSTALL_CODE");
661 : DCHECK(isolate_->concurrent_recompilation_enabled());
662 6319 : isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
663 : }
664 :
665 1730634 : if (CheckAndClearInterrupt(API_INTERRUPT)) {
666 2165 : TRACE_INTERRUPT("API_INTERRUPT");
667 : // Callbacks must be invoked outside of ExecusionAccess lock.
668 2165 : isolate_->InvokeApiInterruptCallbacks();
669 : }
670 :
671 1730634 : if (FLAG_trace_interrupts) {
672 0 : if (!any_interrupt_handled) {
673 0 : PrintF("No interrupt flags set");
674 : }
675 0 : PrintF("]\n");
676 : }
677 :
678 3461268 : isolate_->counters()->stack_interrupts()->Increment();
679 3461268 : isolate_->counters()->runtime_profiler_ticks()->Increment();
680 1730634 : isolate_->runtime_profiler()->MarkCandidatesForOptimization();
681 :
682 3461268 : return ReadOnlyRoots(isolate_).undefined_value();
683 : }
684 :
685 : } // namespace internal
686 120216 : } // namespace v8
687 :
688 : #undef TRACE_INTERRUPT
|