LCOV - code coverage report
Current view: top level - src - execution.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 255 284 89.8 %
Date: 2019-01-20 Functions: 28 31 90.3 %

          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             : namespace v8 {
      16             : namespace internal {
      17             : 
      18     1373370 : void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
      19             :   DCHECK_NOT_NULL(isolate_);
      20             :   thread_local_.set_jslimit(kInterruptLimit);
      21             :   thread_local_.set_climit(kInterruptLimit);
      22     1373370 :   isolate_->heap()->SetStackLimits();
      23     1373370 : }
      24             : 
      25     5676169 : void StackGuard::reset_limits(const ExecutionAccess& lock) {
      26             :   DCHECK_NOT_NULL(isolate_);
      27     5676169 :   thread_local_.set_jslimit(thread_local_.real_jslimit_);
      28     5676169 :   thread_local_.set_climit(thread_local_.real_climit_);
      29     5676169 :   isolate_->heap()->SetStackLimits();
      30     5676165 : }
      31             : 
      32             : namespace {
      33             : 
      34    21612620 : Handle<Object> NormalizeReceiver(Isolate* isolate, Handle<Object> receiver) {
      35             :   // Convert calls on global objects to be calls on the global
      36             :   // receiver instead to avoid having a 'this' pointer which refers
      37             :   // directly to a global object.
      38    43225247 :   if (receiver->IsJSGlobalObject()) {
      39       83782 :     return handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(),
      40       83782 :                   isolate);
      41             :   }
      42    21570735 :   return receiver;
      43             : }
      44             : 
      45             : struct InvokeParams {
      46             :   static InvokeParams SetUpForNew(Isolate* isolate, Handle<Object> constructor,
      47             :                                   Handle<Object> new_target, int argc,
      48             :                                   Handle<Object>* argv);
      49             : 
      50             :   static InvokeParams SetUpForCall(Isolate* isolate, Handle<Object> callable,
      51             :                                    Handle<Object> receiver, int argc,
      52             :                                    Handle<Object>* argv);
      53             : 
      54             :   static InvokeParams SetUpForTryCall(
      55             :       Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
      56             :       int argc, Handle<Object>* argv,
      57             :       Execution::MessageHandling message_handling,
      58             :       MaybeHandle<Object>* exception_out);
      59             : 
      60             :   static InvokeParams SetUpForRunMicrotasks(Isolate* isolate,
      61             :                                             MicrotaskQueue* microtask_queue,
      62             :                                             MaybeHandle<Object>* exception_out);
      63             : 
      64             :   Handle<Object> target;
      65             :   Handle<Object> receiver;
      66             :   int argc;
      67             :   Handle<Object>* argv;
      68             :   Handle<Object> new_target;
      69             : 
      70             :   MicrotaskQueue* microtask_queue;
      71             : 
      72             :   Execution::MessageHandling message_handling;
      73             :   MaybeHandle<Object>* exception_out;
      74             : 
      75             :   bool is_construct;
      76             :   Execution::Target execution_target;
      77             : };
      78             : 
      79             : // static
      80             : InvokeParams InvokeParams::SetUpForNew(Isolate* isolate,
      81             :                                        Handle<Object> constructor,
      82             :                                        Handle<Object> new_target, int argc,
      83             :                                        Handle<Object>* argv) {
      84             :   InvokeParams params;
      85        2013 :   params.target = constructor;
      86        2013 :   params.receiver = isolate->factory()->undefined_value();
      87        2013 :   params.argc = argc;
      88        2013 :   params.argv = argv;
      89        2013 :   params.new_target = new_target;
      90        2013 :   params.microtask_queue = nullptr;
      91        2013 :   params.message_handling = Execution::MessageHandling::kReport;
      92        2013 :   params.exception_out = nullptr;
      93        2013 :   params.is_construct = true;
      94        2013 :   params.execution_target = Execution::Target::kCallable;
      95             :   return params;
      96             : }
      97             : 
      98             : // static
      99             : InvokeParams InvokeParams::SetUpForCall(Isolate* isolate,
     100             :                                         Handle<Object> callable,
     101             :                                         Handle<Object> receiver, int argc,
     102             :                                         Handle<Object>* argv) {
     103             :   InvokeParams params;
     104    21607624 :   params.target = callable;
     105    21607624 :   params.receiver = NormalizeReceiver(isolate, receiver);
     106    21607623 :   params.argc = argc;
     107    21607623 :   params.argv = argv;
     108    21607623 :   params.new_target = isolate->factory()->undefined_value();
     109    21607623 :   params.microtask_queue = nullptr;
     110    21607623 :   params.message_handling = Execution::MessageHandling::kReport;
     111    21607623 :   params.exception_out = nullptr;
     112    21607623 :   params.is_construct = false;
     113    21607623 :   params.execution_target = Execution::Target::kCallable;
     114             :   return params;
     115             : }
     116             : 
     117             : // static
     118             : InvokeParams InvokeParams::SetUpForTryCall(
     119             :     Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
     120             :     int argc, Handle<Object>* argv, Execution::MessageHandling message_handling,
     121             :     MaybeHandle<Object>* exception_out) {
     122             :   InvokeParams params;
     123        4998 :   params.target = callable;
     124        4998 :   params.receiver = NormalizeReceiver(isolate, receiver);
     125        5003 :   params.argc = argc;
     126        5003 :   params.argv = argv;
     127        5003 :   params.new_target = isolate->factory()->undefined_value();
     128        5003 :   params.microtask_queue = nullptr;
     129        5003 :   params.message_handling = message_handling;
     130        5003 :   params.exception_out = exception_out;
     131        5003 :   params.is_construct = false;
     132        5003 :   params.execution_target = Execution::Target::kCallable;
     133             :   return params;
     134             : }
     135             : 
     136             : // static
     137             : InvokeParams InvokeParams::SetUpForRunMicrotasks(
     138             :     Isolate* isolate, MicrotaskQueue* microtask_queue,
     139             :     MaybeHandle<Object>* exception_out) {
     140             :   auto undefined = isolate->factory()->undefined_value();
     141             :   InvokeParams params;
     142       52430 :   params.target = undefined;
     143       52430 :   params.receiver = undefined;
     144       52430 :   params.argc = 0;
     145       52430 :   params.argv = nullptr;
     146       52430 :   params.new_target = undefined;
     147       52430 :   params.microtask_queue = microtask_queue;
     148       52430 :   params.message_handling = Execution::MessageHandling::kReport;
     149       52430 :   params.exception_out = exception_out;
     150       52430 :   params.is_construct = false;
     151       52430 :   params.execution_target = Execution::Target::kRunMicrotasks;
     152             :   return params;
     153             : }
     154             : 
     155    21652818 : Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
     156             :                      bool is_construct) {
     157    21652818 :   if (is_construct) {
     158             :     DCHECK_EQ(Execution::Target::kCallable, execution_target);
     159        1106 :     return BUILTIN_CODE(isolate, JSConstructEntry);
     160    21651712 :   } else if (execution_target == Execution::Target::kCallable) {
     161             :     DCHECK(!is_construct);
     162    21599282 :     return BUILTIN_CODE(isolate, JSEntry);
     163       52430 :   } else if (execution_target == Execution::Target::kRunMicrotasks) {
     164             :     DCHECK(!is_construct);
     165       52430 :     return BUILTIN_CODE(isolate, JSRunMicrotasksEntry);
     166             :   }
     167           0 :   UNREACHABLE();
     168             : }
     169             : 
     170    21667064 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
     171             :                                                  const InvokeParams& params) {
     172    21667064 :   RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kInvoke);
     173             :   DCHECK(!params.receiver->IsJSGlobalObject());
     174             :   DCHECK_LE(params.argc, FixedArray::kMaxLength);
     175             : 
     176             : #ifdef USE_SIMULATOR
     177             :   // Simulators use separate stacks for C++ and JS. JS stack overflow checks
     178             :   // are performed whenever a JS function is called. However, it can be the case
     179             :   // that the C++ stack grows faster than the JS stack, resulting in an overflow
     180             :   // there. Add a check here to make that less likely.
     181             :   StackLimitCheck check(isolate);
     182             :   if (check.HasOverflowed()) {
     183             :     isolate->StackOverflow();
     184             :     if (params.message_handling == Execution::MessageHandling::kReport) {
     185             :       isolate->ReportPendingMessages();
     186             :     }
     187             :     return MaybeHandle<Object>();
     188             :   }
     189             : #endif
     190             : 
     191             :   // api callbacks can be called directly, unless we want to take the detour
     192             :   // through JS to set up a frame for break-at-entry.
     193    43334142 :   if (params.target->IsJSFunction()) {
     194    21471413 :     Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
     195    64418246 :     if ((!params.is_construct || function->IsConstructor()) &&
     196    64428693 :         function->shared()->IsApiFunction() &&
     197    21485878 :         !function->shared()->BreakAtEntry()) {
     198       14236 :       SaveContext save(isolate);
     199       28472 :       isolate->set_context(function->context());
     200             :       DCHECK(function->context()->global_object()->IsJSGlobalObject());
     201             : 
     202             :       Handle<Object> receiver = params.is_construct
     203             :                                     ? isolate->factory()->the_hole_value()
     204       27565 :                                     : params.receiver;
     205             :       auto value = Builtins::InvokeApiFunction(
     206             :           isolate, params.is_construct, function, receiver, params.argc,
     207       28472 :           params.argv, Handle<HeapObject>::cast(params.new_target));
     208             :       bool has_exception = value.is_null();
     209             :       DCHECK(has_exception == isolate->has_pending_exception());
     210       14236 :       if (has_exception) {
     211         216 :         if (params.message_handling == Execution::MessageHandling::kReport) {
     212         216 :           isolate->ReportPendingMessages();
     213             :         }
     214         216 :         return MaybeHandle<Object>();
     215             :       } else {
     216       14020 :         isolate->clear_pending_message();
     217             :       }
     218       14020 :       return value;
     219             :     }
     220             :   }
     221             : 
     222             :   // Entering JavaScript.
     223             :   VMState<JS> state(isolate);
     224    21652827 :   CHECK(AllowJavascriptExecution::IsAllowed(isolate));
     225    21652825 :   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    21652827 :   if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
     233           5 :     V8::GetCurrentPlatform()->DumpWithoutCrashing();
     234           5 :     return isolate->factory()->undefined_value();
     235             :   }
     236             : 
     237             :   // Placeholder for return value.
     238    21652823 :   Object value;
     239             : 
     240             :   Handle<Code> code =
     241    21652823 :       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    21652820 :     SaveContext save(isolate);
     246             :     SealHandleScope shs(isolate);
     247             : 
     248    21652822 :     if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
     249             : 
     250    21652823 :     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    43200786 :           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    21600395 :       Address** argv = reinterpret_cast<Address**>(params.argv);
     265    21600395 :       RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
     266             :       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
     267    43200795 :                                      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      104860 :           JSEntryFunction::FromAddress(isolate, code->InstructionStart());
     279             : 
     280       52430 :       RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
     281             :       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
     282      104860 :                                      params.microtask_queue));
     283    21652828 :     }
     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    21652819 :   if (has_exception) {
     296      109358 :     if (params.message_handling == Execution::MessageHandling::kReport) {
     297      109353 :       isolate->ReportPendingMessages();
     298             :     }
     299      109358 :     return MaybeHandle<Object>();
     300             :   } else {
     301    21543461 :     isolate->clear_pending_message();
     302             :   }
     303             : 
     304    21543452 :   return Handle<Object>(value, isolate);
     305             : }
     306             : 
     307       57433 : MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
     308             :                                        const InvokeParams& params) {
     309             :   bool is_termination = false;
     310             :   MaybeHandle<Object> maybe_result;
     311       57433 :   if (params.exception_out != nullptr) {
     312       52705 :     *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       57433 :     v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
     323       57432 :     catcher.SetVerbose(false);
     324       57432 :     catcher.SetCaptureMessage(false);
     325             : 
     326       57431 :     maybe_result = Invoke(isolate, params);
     327             : 
     328       57437 :     if (maybe_result.is_null()) {
     329             :       DCHECK(isolate->has_pending_exception());
     330         120 :       if (isolate->pending_exception() ==
     331             :           ReadOnlyRoots(isolate).termination_exception()) {
     332             :         is_termination = true;
     333             :       } else {
     334          95 :         if (params.exception_out != nullptr) {
     335             :           DCHECK(catcher.HasCaught());
     336             :           DCHECK(isolate->external_caught_exception());
     337         180 :           *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
     338             :         }
     339             :       }
     340         120 :       if (params.message_handling == Execution::MessageHandling::kReport) {
     341         115 :         isolate->OptionalRescheduleException(true);
     342             :       }
     343       57437 :     }
     344             :   }
     345             : 
     346             :   // Re-request terminate execution interrupt to trigger later.
     347       57431 :   if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
     348             : 
     349       57431 :   return maybe_result;
     350             : }
     351             : 
     352             : }  // namespace
     353             : 
     354             : // static
     355    21607624 : MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
     356             :                                     Handle<Object> receiver, int argc,
     357             :                                     Handle<Object> argv[]) {
     358             :   return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
     359    21607623 :                                                     argc, argv));
     360             : }
     361             : 
     362             : // static
     363         782 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
     364             :                                    int argc, Handle<Object> argv[]) {
     365         782 :   return New(isolate, constructor, constructor, argc, argv);
     366             : }
     367             : 
     368             : // static
     369        2013 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
     370             :                                    Handle<Object> new_target, int argc,
     371             :                                    Handle<Object> argv[]) {
     372             :   return Invoke(isolate, InvokeParams::SetUpForNew(isolate, constructor,
     373        2013 :                                                    new_target, argc, argv));
     374             : }
     375             : 
     376             : // static
     377        4998 : 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             :       InvokeParams::SetUpForTryCall(isolate, callable, receiver, argc, argv,
     386        5003 :                                     message_handling, exception_out));
     387             : }
     388             : 
     389             : // static
     390       52430 : MaybeHandle<Object> Execution::TryRunMicrotasks(
     391             :     Isolate* isolate, MicrotaskQueue* microtask_queue,
     392             :     MaybeHandle<Object>* exception_out) {
     393             :   return InvokeWithTryCatch(
     394             :       isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
     395       52430 :                                                    exception_out));
     396             : }
     397             : 
     398        1851 : void StackGuard::SetStackLimit(uintptr_t limit) {
     399        1851 :   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        1851 :   if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
     404             :     thread_local_.set_jslimit(jslimit);
     405             :   }
     406        1851 :   if (thread_local_.climit() == thread_local_.real_climit_) {
     407             :     thread_local_.set_climit(limit);
     408             :   }
     409        1851 :   thread_local_.real_climit_ = limit;
     410        1851 :   thread_local_.real_jslimit_ = jslimit;
     411        1851 : }
     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     8876232 : void StackGuard::PushInterruptsScope(InterruptsScope* scope) {
     441     4438102 :   ExecutionAccess access(isolate_);
     442             :   DCHECK_NE(scope->mode_, InterruptsScope::kNoop);
     443     4438130 :   if (scope->mode_ == InterruptsScope::kPostponeInterrupts) {
     444             :     // Intercept already requested interrupts.
     445     4407361 :     int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
     446     4407361 :     scope->intercepted_flags_ = intercepted;
     447     4407361 :     thread_local_.interrupt_flags_ &= ~intercepted;
     448             :   } else {
     449             :     DCHECK_EQ(scope->mode_, InterruptsScope::kRunInterrupts);
     450             :     // Restore postponed interrupts.
     451             :     int restored_flags = 0;
     452       46648 :     for (InterruptsScope* current = thread_local_.interrupt_scopes_;
     453             :          current != nullptr; current = current->prev_) {
     454       15879 :       restored_flags |= (current->intercepted_flags_ & scope->intercept_mask_);
     455       15879 :       current->intercepted_flags_ &= ~scope->intercept_mask_;
     456             :     }
     457       30769 :     thread_local_.interrupt_flags_ |= restored_flags;
     458             :   }
     459     4438130 :   if (!has_pending_interrupts(access)) reset_limits(access);
     460             :   // Add scope to the chain.
     461     4438126 :   scope->prev_ = thread_local_.interrupt_scopes_;
     462     4438126 :   thread_local_.interrupt_scopes_ = scope;
     463     4438138 : }
     464             : 
     465     8876240 : void StackGuard::PopInterruptsScope() {
     466     4438107 :   ExecutionAccess access(isolate_);
     467     4438133 :   InterruptsScope* top = thread_local_.interrupt_scopes_;
     468             :   DCHECK_NE(top->mode_, InterruptsScope::kNoop);
     469     4438133 :   if (top->mode_ == InterruptsScope::kPostponeInterrupts) {
     470             :     // Make intercepted interrupts active.
     471             :     DCHECK_EQ(thread_local_.interrupt_flags_ & top->intercept_mask_, 0);
     472     4407364 :     thread_local_.interrupt_flags_ |= top->intercepted_flags_;
     473             :   } else {
     474             :     DCHECK_EQ(top->mode_, InterruptsScope::kRunInterrupts);
     475             :     // Postpone existing interupts if needed.
     476       30769 :     if (top->prev_) {
     477       74770 :       for (int interrupt = 1; interrupt < ALL_INTERRUPTS;
     478             :            interrupt = interrupt << 1) {
     479       74770 :         InterruptFlag flag = static_cast<InterruptFlag>(interrupt);
     480       74807 :         if ((thread_local_.interrupt_flags_ & flag) &&
     481          37 :             top->prev_->Intercept(flag)) {
     482          27 :           thread_local_.interrupt_flags_ &= ~flag;
     483             :         }
     484             :       }
     485             :     }
     486             :   }
     487     4438133 :   if (has_pending_interrupts(access)) set_interrupt_limits(access);
     488             :   // Remove scope from chain.
     489     4438133 :   thread_local_.interrupt_scopes_ = top->prev_;
     490     4438130 : }
     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     1308468 : void StackGuard::RequestInterrupt(InterruptFlag flag) {
     500     1308468 :   ExecutionAccess access(isolate_);
     501             :   // Check the chain of InterruptsScope for interception.
     502     1384695 :   if (thread_local_.interrupt_scopes_ &&
     503       76227 :       thread_local_.interrupt_scopes_->Intercept(flag)) {
     504     1308468 :     return;
     505             :   }
     506             : 
     507             :   // Not intercepted.  Set as active interrupt flag.
     508     1232884 :   thread_local_.interrupt_flags_ |= flag;
     509     1232884 :   set_interrupt_limits(access);
     510             : 
     511             :   // If this isolate is waiting in a futex, notify it to wake up.
     512     1232884 :   isolate_->futex_wait_list_node()->NotifyWake();
     513             : }
     514             : 
     515             : 
     516       31178 : void StackGuard::ClearInterrupt(InterruptFlag flag) {
     517       31178 :   ExecutionAccess access(isolate_);
     518             :   // Clear the interrupt flag from the chain of InterruptsScope.
     519       59622 :   for (InterruptsScope* current = thread_local_.interrupt_scopes_;
     520             :        current != nullptr; current = current->prev_) {
     521       28444 :     current->intercepted_flags_ &= ~flag;
     522             :   }
     523             : 
     524             :   // Clear the interrupt flag from the active interrupt flags.
     525       31178 :   thread_local_.interrupt_flags_ &= ~flag;
     526       31178 :   if (!has_pending_interrupts(access)) reset_limits(access);
     527       31178 : }
     528             : 
     529             : 
     530     1241433 : bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
     531     1241433 :   ExecutionAccess access(isolate_);
     532     1241433 :   bool result = (thread_local_.interrupt_flags_ & flag);
     533     1241433 :   thread_local_.interrupt_flags_ &= ~flag;
     534     1241433 :   if (!has_pending_interrupts(access)) reset_limits(access);
     535     1241433 :   return result;
     536             : }
     537             : 
     538             : 
     539       24256 : char* StackGuard::ArchiveStackGuard(char* to) {
     540       24256 :   ExecutionAccess access(isolate_);
     541       24256 :   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       24256 :   isolate_->heap()->SetStackLimits();
     550       24256 :   thread_local_ = blank;
     551             : 
     552       48512 :   return to + sizeof(ThreadLocal);
     553             : }
     554             : 
     555             : 
     556       24256 : char* StackGuard::RestoreStackGuard(char* from) {
     557       24256 :   ExecutionAccess access(isolate_);
     558       24256 :   MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
     559       24256 :   isolate_->heap()->SetStackLimits();
     560       48512 :   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       93056 : void StackGuard::ThreadLocal::Clear() {
     572       93056 :   real_jslimit_ = kIllegalLimit;
     573             :   set_jslimit(kIllegalLimit);
     574       93056 :   real_climit_ = kIllegalLimit;
     575             :   set_climit(kIllegalLimit);
     576       93056 :   interrupt_scopes_ = nullptr;
     577       93056 :   interrupt_flags_ = 0;
     578       93056 : }
     579             : 
     580             : 
     581       74719 : bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
     582             :   bool should_set_stack_limits = false;
     583       74719 :   if (real_climit_ == kIllegalLimit) {
     584       70028 :     const uintptr_t kLimitSize = FLAG_stack_size * KB;
     585             :     DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
     586       70028 :     uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
     587       70028 :     real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
     588             :     set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
     589       70028 :     real_climit_ = limit;
     590             :     set_climit(limit);
     591             :     should_set_stack_limits = true;
     592             :   }
     593       74719 :   interrupt_scopes_ = nullptr;
     594       74719 :   interrupt_flags_ = 0;
     595       74719 :   return should_set_stack_limits;
     596             : }
     597             : 
     598             : 
     599        5918 : void StackGuard::ClearThread(const ExecutionAccess& lock) {
     600        5918 :   thread_local_.Clear();
     601        5918 :   isolate_->heap()->SetStackLimits();
     602        5918 : }
     603             : 
     604             : 
     605       74719 : void StackGuard::InitThread(const ExecutionAccess& lock) {
     606       74719 :   if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
     607       74719 :   Isolate::PerIsolateThreadData* per_thread =
     608       74719 :       isolate_->FindOrAllocatePerThreadDataForThisThread();
     609             :   uintptr_t stored_limit = per_thread->stack_limit();
     610             :   // You should hold the ExecutionAccess lock when you call this.
     611       74719 :   if (stored_limit != 0) {
     612         190 :     SetStackLimit(stored_limit);
     613             :   }
     614       74719 : }
     615             : 
     616             : 
     617             : // --- C a l l s   t o   n a t i v e s ---
     618             : 
     619      249030 : Object StackGuard::HandleInterrupts() {
     620             :   if (FLAG_verify_predictable) {
     621             :     // Advance synthetic time by making a time request.
     622      254187 :     isolate_->heap()->MonotonicallyIncreasingTimeInMs();
     623             :   }
     624             : 
     625             :   bool any_interrupt_handled = false;
     626      249030 :   if (FLAG_trace_interrupts) {
     627           0 :     PrintF("[Handling interrupts: ");
     628             :   }
     629             : 
     630      249030 :   if (CheckAndClearInterrupt(GC_REQUEST)) {
     631       18500 :     if (FLAG_trace_interrupts) {
     632           0 :       PrintF("GC_REQUEST");
     633             :       any_interrupt_handled = true;
     634             :     }
     635       18500 :     isolate_->heap()->HandleGCRequest();
     636             :   }
     637             : 
     638      249030 :   if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
     639        1239 :     if (FLAG_trace_interrupts) {
     640           0 :       if (any_interrupt_handled) PrintF(", ");
     641           0 :       PrintF("TERMINATE_EXECUTION");
     642             :       any_interrupt_handled = true;
     643             :     }
     644        1239 :     return isolate_->TerminateExecution();
     645             :   }
     646             : 
     647      247791 :   if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
     648          34 :     if (FLAG_trace_interrupts) {
     649           0 :       if (any_interrupt_handled) PrintF(", ");
     650           0 :       PrintF("DEOPT_MARKED_ALLOCATION_SITES");
     651             :       any_interrupt_handled = true;
     652             :     }
     653          34 :     isolate_->heap()->DeoptMarkedAllocationSites();
     654             :   }
     655             : 
     656      247791 :   if (CheckAndClearInterrupt(INSTALL_CODE)) {
     657        6396 :     if (FLAG_trace_interrupts) {
     658           0 :       if (any_interrupt_handled) PrintF(", ");
     659           0 :       PrintF("INSTALL_CODE");
     660             :       any_interrupt_handled = true;
     661             :     }
     662             :     DCHECK(isolate_->concurrent_recompilation_enabled());
     663       12792 :     isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
     664             :   }
     665             : 
     666      247791 :   if (CheckAndClearInterrupt(API_INTERRUPT)) {
     667        2126 :     if (FLAG_trace_interrupts) {
     668           0 :       if (any_interrupt_handled) PrintF(", ");
     669           0 :       PrintF("API_INTERRUPT");
     670             :       any_interrupt_handled = true;
     671             :     }
     672             :     // Callbacks must be invoked outside of ExecusionAccess lock.
     673        2126 :     isolate_->InvokeApiInterruptCallbacks();
     674             :   }
     675             : 
     676      247791 :   if (FLAG_trace_interrupts) {
     677           0 :     if (!any_interrupt_handled) {
     678           0 :       PrintF("No interrupt flags set");
     679             :     }
     680           0 :     PrintF("]\n");
     681             :   }
     682             : 
     683      495582 :   isolate_->counters()->stack_interrupts()->Increment();
     684      495582 :   isolate_->counters()->runtime_profiler_ticks()->Increment();
     685      495582 :   isolate_->runtime_profiler()->MarkCandidatesForOptimization();
     686             : 
     687      495582 :   return ReadOnlyRoots(isolate_).undefined_value();
     688             : }
     689             : 
     690             : }  // namespace internal
     691      183867 : }  // namespace v8

Generated by: LCOV version 1.10