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

Generated by: LCOV version 1.10