LCOV - code coverage report
Current view: top level - src - execution.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 256 276 92.8 %
Date: 2019-03-21 Functions: 27 30 90.0 %

          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

Generated by: LCOV version 1.10