LCOV - code coverage report
Current view: top level - src - execution.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 254 283 89.8 %
Date: 2019-02-19 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     1137292 : 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     1137292 :   isolate_->heap()->SetStackLimits();
      23     1137292 : }
      24             : 
      25     5585843 : void StackGuard::reset_limits(const ExecutionAccess& lock) {
      26             :   DCHECK_NOT_NULL(isolate_);
      27     5585843 :   thread_local_.set_jslimit(thread_local_.real_jslimit_);
      28     5585843 :   thread_local_.set_climit(thread_local_.real_climit_);
      29     5585843 :   isolate_->heap()->SetStackLimits();
      30     5585842 : }
      31             : 
      32             : namespace {
      33             : 
      34    21589026 : 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    43178058 :   if (receiver->IsJSGlobalObject()) {
      39       69105 :     return handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(),
      40       69105 :                   isolate);
      41             :   }
      42    21554478 :   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        1863 :   params.target = constructor;
      86        1863 :   params.receiver = isolate->factory()->undefined_value();
      87        1863 :   params.argc = argc;
      88        1863 :   params.argv = argv;
      89        1863 :   params.new_target = new_target;
      90        1863 :   params.microtask_queue = nullptr;
      91        1863 :   params.message_handling = Execution::MessageHandling::kReport;
      92        1863 :   params.exception_out = nullptr;
      93        1863 :   params.is_construct = true;
      94        1863 :   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    21584134 :   params.target = callable;
     105    21584134 :   params.receiver = NormalizeReceiver(isolate, receiver);
     106    21584138 :   params.argc = argc;
     107    21584138 :   params.argv = argv;
     108    21584138 :   params.new_target = isolate->factory()->undefined_value();
     109    21584138 :   params.microtask_queue = nullptr;
     110    21584138 :   params.message_handling = Execution::MessageHandling::kReport;
     111    21584138 :   params.exception_out = nullptr;
     112    21584138 :   params.is_construct = false;
     113    21584138 :   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        4892 :   params.target = callable;
     124        4892 :   params.receiver = NormalizeReceiver(isolate, receiver);
     125        4894 :   params.argc = argc;
     126        4894 :   params.argv = argv;
     127        4894 :   params.new_target = isolate->factory()->undefined_value();
     128        4894 :   params.microtask_queue = nullptr;
     129        4894 :   params.message_handling = message_handling;
     130        4894 :   params.exception_out = exception_out;
     131        4894 :   params.is_construct = false;
     132        4894 :   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       51534 :   params.target = undefined;
     143       51534 :   params.receiver = undefined;
     144       51534 :   params.argc = 0;
     145       51534 :   params.argv = nullptr;
     146       51534 :   params.new_target = undefined;
     147       51534 :   params.microtask_queue = microtask_queue;
     148       51534 :   params.message_handling = Execution::MessageHandling::kReport;
     149       51534 :   params.exception_out = exception_out;
     150       51534 :   params.is_construct = false;
     151       51534 :   params.execution_target = Execution::Target::kRunMicrotasks;
     152             :   return params;
     153             : }
     154             : 
     155    21629942 : Handle<Code> JSEntry(Isolate* isolate, Execution::Target execution_target,
     156             :                      bool is_construct) {
     157    21629942 :   if (is_construct) {
     158             :     DCHECK_EQ(Execution::Target::kCallable, execution_target);
     159        1105 :     return BUILTIN_CODE(isolate, JSConstructEntry);
     160    21628837 :   } else if (execution_target == Execution::Target::kCallable) {
     161             :     DCHECK(!is_construct);
     162    21577303 :     return BUILTIN_CODE(isolate, JSEntry);
     163       51534 :   } else if (execution_target == Execution::Target::kRunMicrotasks) {
     164             :     DCHECK(!is_construct);
     165       51534 :     return BUILTIN_CODE(isolate, JSRunMicrotasksEntry);
     166             :   }
     167           0 :   UNREACHABLE();
     168             : }
     169             : 
     170    21642427 : V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
     171             :                                                  const InvokeParams& params) {
     172    21642427 :   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    43284872 :   if (params.target->IsJSFunction()) {
     194    21450192 :     Handle<JSFunction> function = Handle<JSFunction>::cast(params.target);
     195    64354295 :     if ((!params.is_construct || function->IsConstructor()) &&
     196    64363288 :         function->shared()->IsApiFunction() &&
     197    21462911 :         !function->shared()->BreakAtEntry()) {
     198       12478 :       SaveAndSwitchContext save(isolate, function->context());
     199             :       DCHECK(function->context()->global_object()->IsJSGlobalObject());
     200             : 
     201             :       Handle<Object> receiver = params.is_construct
     202             :                                     ? isolate->factory()->the_hole_value()
     203       24196 :                                     : params.receiver;
     204             :       auto value = Builtins::InvokeApiFunction(
     205             :           isolate, params.is_construct, function, receiver, params.argc,
     206       24954 :           params.argv, Handle<HeapObject>::cast(params.new_target));
     207             :       bool has_exception = value.is_null();
     208             :       DCHECK(has_exception == isolate->has_pending_exception());
     209       12478 :       if (has_exception) {
     210         206 :         if (params.message_handling == Execution::MessageHandling::kReport) {
     211         206 :           isolate->ReportPendingMessages();
     212             :         }
     213         206 :         return MaybeHandle<Object>();
     214             :       } else {
     215       12272 :         isolate->clear_pending_message();
     216             :       }
     217       12272 :       return value;
     218             :     }
     219             :   }
     220             : 
     221             :   // Entering JavaScript.
     222             :   VMState<JS> state(isolate);
     223    21629962 :   CHECK(AllowJavascriptExecution::IsAllowed(isolate));
     224    21629950 :   if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
     225           5 :     isolate->ThrowIllegalOperation();
     226           5 :     if (params.message_handling == Execution::MessageHandling::kReport) {
     227           5 :       isolate->ReportPendingMessages();
     228             :     }
     229           5 :     return MaybeHandle<Object>();
     230             :   }
     231    21629945 :   if (!DumpOnJavascriptExecution::IsAllowed(isolate)) {
     232           5 :     V8::GetCurrentPlatform()->DumpWithoutCrashing();
     233           5 :     return isolate->factory()->undefined_value();
     234             :   }
     235             : 
     236             :   // Placeholder for return value.
     237    21629940 :   Object value;
     238             : 
     239             :   Handle<Code> code =
     240    21629940 :       JSEntry(isolate, params.execution_target, params.is_construct);
     241             :   {
     242             :     // Save and restore context around invocation and block the
     243             :     // allocation of handles without explicit handle scopes.
     244    21629936 :     SaveContext save(isolate);
     245             :     SealHandleScope shs(isolate);
     246             : 
     247    21629940 :     if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
     248             : 
     249    21629943 :     if (params.execution_target == Execution::Target::kCallable) {
     250             :       // clang-format off
     251             :       // {new_target}, {target}, {receiver}, return value: tagged pointers
     252             :       // {argv}: pointer to array of tagged pointers
     253             :       using JSEntryFunction = GeneratedCode<Address(
     254             :           Address root_register_value, Address new_target, Address target,
     255             :           Address receiver, intptr_t argc, Address** argv)>;
     256             :       // clang-format on
     257             :       JSEntryFunction stub_entry =
     258    43156815 :           JSEntryFunction::FromAddress(isolate, code->InstructionStart());
     259             : 
     260             :       Address orig_func = params.new_target->ptr();
     261             :       Address func = params.target->ptr();
     262             :       Address recv = params.receiver->ptr();
     263    21578407 :       Address** argv = reinterpret_cast<Address**>(params.argv);
     264    21578407 :       RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
     265             :       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
     266    43156820 :                                      orig_func, func, recv, params.argc, argv));
     267             :     } else {
     268             :       DCHECK_EQ(Execution::Target::kRunMicrotasks, params.execution_target);
     269             : 
     270             :       // clang-format off
     271             :       // return value: tagged pointers
     272             :       // {microtask_queue}: pointer to a C++ object
     273             :       using JSEntryFunction = GeneratedCode<Address(
     274             :           Address root_register_value, MicrotaskQueue* microtask_queue)>;
     275             :       // clang-format on
     276             :       JSEntryFunction stub_entry =
     277      103068 :           JSEntryFunction::FromAddress(isolate, code->InstructionStart());
     278             : 
     279       51534 :       RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
     280             :       value = Object(stub_entry.Call(isolate->isolate_data()->isolate_root(),
     281      103068 :                                      params.microtask_queue));
     282    21629948 :     }
     283             :   }
     284             : 
     285             : #ifdef VERIFY_HEAP
     286             :   if (FLAG_verify_heap) {
     287             :     value->ObjectVerify(isolate);
     288             :   }
     289             : #endif
     290             : 
     291             :   // Update the pending exception flag and return the value.
     292             :   bool has_exception = value->IsException(isolate);
     293             :   DCHECK(has_exception == isolate->has_pending_exception());
     294    21629945 :   if (has_exception) {
     295      108947 :     if (params.message_handling == Execution::MessageHandling::kReport) {
     296      108942 :       isolate->ReportPendingMessages();
     297             :     }
     298      108947 :     return MaybeHandle<Object>();
     299             :   } else {
     300    21520998 :     isolate->clear_pending_message();
     301             :   }
     302             : 
     303    21520987 :   return Handle<Object>(value, isolate);
     304             : }
     305             : 
     306       56427 : MaybeHandle<Object> InvokeWithTryCatch(Isolate* isolate,
     307             :                                        const InvokeParams& params) {
     308             :   bool is_termination = false;
     309             :   MaybeHandle<Object> maybe_result;
     310       56427 :   if (params.exception_out != nullptr) {
     311       51788 :     *params.exception_out = MaybeHandle<Object>();
     312             :   }
     313             :   DCHECK_IMPLIES(
     314             :       params.message_handling == Execution::MessageHandling::kKeepPending,
     315             :       params.exception_out == nullptr);
     316             :   // Enter a try-block while executing the JavaScript code. To avoid
     317             :   // duplicate error printing it must be non-verbose.  Also, to avoid
     318             :   // creating message objects during stack overflow we shouldn't
     319             :   // capture messages.
     320             :   {
     321       56427 :     v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
     322       56427 :     catcher.SetVerbose(false);
     323       56427 :     catcher.SetCaptureMessage(false);
     324             : 
     325       56428 :     maybe_result = Invoke(isolate, params);
     326             : 
     327       56427 :     if (maybe_result.is_null()) {
     328             :       DCHECK(isolate->has_pending_exception());
     329          90 :       if (isolate->pending_exception() ==
     330             :           ReadOnlyRoots(isolate).termination_exception()) {
     331             :         is_termination = true;
     332             :       } else {
     333          65 :         if (params.exception_out != nullptr) {
     334             :           DCHECK(catcher.HasCaught());
     335             :           DCHECK(isolate->external_caught_exception());
     336         120 :           *params.exception_out = v8::Utils::OpenHandle(*catcher.Exception());
     337             :         }
     338             :       }
     339          90 :       if (params.message_handling == Execution::MessageHandling::kReport) {
     340          85 :         isolate->OptionalRescheduleException(true);
     341             :       }
     342       56427 :     }
     343             :   }
     344             : 
     345             :   // Re-request terminate execution interrupt to trigger later.
     346       56429 :   if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
     347             : 
     348       56429 :   return maybe_result;
     349             : }
     350             : 
     351             : }  // namespace
     352             : 
     353             : // static
     354    21584134 : MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
     355             :                                     Handle<Object> receiver, int argc,
     356             :                                     Handle<Object> argv[]) {
     357             :   return Invoke(isolate, InvokeParams::SetUpForCall(isolate, callable, receiver,
     358    21584138 :                                                     argc, argv));
     359             : }
     360             : 
     361             : // static
     362         781 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
     363             :                                    int argc, Handle<Object> argv[]) {
     364         781 :   return New(isolate, constructor, constructor, argc, argv);
     365             : }
     366             : 
     367             : // static
     368        1863 : MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
     369             :                                    Handle<Object> new_target, int argc,
     370             :                                    Handle<Object> argv[]) {
     371             :   return Invoke(isolate, InvokeParams::SetUpForNew(isolate, constructor,
     372        1863 :                                                    new_target, argc, argv));
     373             : }
     374             : 
     375             : // static
     376        4892 : MaybeHandle<Object> Execution::TryCall(Isolate* isolate,
     377             :                                        Handle<Object> callable,
     378             :                                        Handle<Object> receiver, int argc,
     379             :                                        Handle<Object> argv[],
     380             :                                        MessageHandling message_handling,
     381             :                                        MaybeHandle<Object>* exception_out) {
     382             :   return InvokeWithTryCatch(
     383             :       isolate,
     384             :       InvokeParams::SetUpForTryCall(isolate, callable, receiver, argc, argv,
     385        4894 :                                     message_handling, exception_out));
     386             : }
     387             : 
     388             : // static
     389       51534 : MaybeHandle<Object> Execution::TryRunMicrotasks(
     390             :     Isolate* isolate, MicrotaskQueue* microtask_queue,
     391             :     MaybeHandle<Object>* exception_out) {
     392             :   return InvokeWithTryCatch(
     393             :       isolate, InvokeParams::SetUpForRunMicrotasks(isolate, microtask_queue,
     394       51534 :                                                    exception_out));
     395             : }
     396             : 
     397        1851 : void StackGuard::SetStackLimit(uintptr_t limit) {
     398        1851 :   ExecutionAccess access(isolate_);
     399             :   // If the current limits are special (e.g. due to a pending interrupt) then
     400             :   // leave them alone.
     401             :   uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
     402        1851 :   if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
     403             :     thread_local_.set_jslimit(jslimit);
     404             :   }
     405        1851 :   if (thread_local_.climit() == thread_local_.real_climit_) {
     406             :     thread_local_.set_climit(limit);
     407             :   }
     408        1851 :   thread_local_.real_climit_ = limit;
     409        1851 :   thread_local_.real_jslimit_ = jslimit;
     410        1851 : }
     411             : 
     412             : 
     413           0 : void StackGuard::AdjustStackLimitForSimulator() {
     414           0 :   ExecutionAccess access(isolate_);
     415           0 :   uintptr_t climit = thread_local_.real_climit_;
     416             :   // If the current limits are special (e.g. due to a pending interrupt) then
     417             :   // leave them alone.
     418             :   uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
     419           0 :   if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
     420             :     thread_local_.set_jslimit(jslimit);
     421           0 :     isolate_->heap()->SetStackLimits();
     422             :   }
     423           0 : }
     424             : 
     425             : 
     426           0 : void StackGuard::EnableInterrupts() {
     427           0 :   ExecutionAccess access(isolate_);
     428           0 :   if (has_pending_interrupts(access)) {
     429           0 :     set_interrupt_limits(access);
     430             :   }
     431           0 : }
     432             : 
     433             : 
     434           0 : void StackGuard::DisableInterrupts() {
     435           0 :   ExecutionAccess access(isolate_);
     436           0 :   reset_limits(access);
     437           0 : }
     438             : 
     439     8762885 : void StackGuard::PushInterruptsScope(InterruptsScope* scope) {
     440     4381439 :   ExecutionAccess access(isolate_);
     441             :   DCHECK_NE(scope->mode_, InterruptsScope::kNoop);
     442     4381446 :   if (scope->mode_ == InterruptsScope::kPostponeInterrupts) {
     443             :     // Intercept already requested interrupts.
     444     4350887 :     int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
     445     4350887 :     scope->intercepted_flags_ = intercepted;
     446     4350887 :     thread_local_.interrupt_flags_ &= ~intercepted;
     447             :   } else {
     448             :     DCHECK_EQ(scope->mode_, InterruptsScope::kRunInterrupts);
     449             :     // Restore postponed interrupts.
     450             :     int restored_flags = 0;
     451       46368 :     for (InterruptsScope* current = thread_local_.interrupt_scopes_;
     452             :          current != nullptr; current = current->prev_) {
     453       15809 :       restored_flags |= (current->intercepted_flags_ & scope->intercept_mask_);
     454       15809 :       current->intercepted_flags_ &= ~scope->intercept_mask_;
     455             :     }
     456       30559 :     thread_local_.interrupt_flags_ |= restored_flags;
     457             :   }
     458     4381446 :   if (!has_pending_interrupts(access)) reset_limits(access);
     459             :   // Add scope to the chain.
     460     4381446 :   scope->prev_ = thread_local_.interrupt_scopes_;
     461     4381446 :   thread_local_.interrupt_scopes_ = scope;
     462     4381452 : }
     463             : 
     464     8762892 : void StackGuard::PopInterruptsScope() {
     465     4381440 :   ExecutionAccess access(isolate_);
     466     4381452 :   InterruptsScope* top = thread_local_.interrupt_scopes_;
     467             :   DCHECK_NE(top->mode_, InterruptsScope::kNoop);
     468     4381452 :   if (top->mode_ == InterruptsScope::kPostponeInterrupts) {
     469             :     // Make intercepted interrupts active.
     470             :     DCHECK_EQ(thread_local_.interrupt_flags_ & top->intercept_mask_, 0);
     471     4350893 :     thread_local_.interrupt_flags_ |= top->intercepted_flags_;
     472             :   } else {
     473             :     DCHECK_EQ(top->mode_, InterruptsScope::kRunInterrupts);
     474             :     // Postpone existing interupts if needed.
     475       30559 :     if (top->prev_) {
     476       74450 :       for (int interrupt = 1; interrupt < ALL_INTERRUPTS;
     477             :            interrupt = interrupt << 1) {
     478       74450 :         InterruptFlag flag = static_cast<InterruptFlag>(interrupt);
     479       74478 :         if ((thread_local_.interrupt_flags_ & flag) &&
     480          28 :             top->prev_->Intercept(flag)) {
     481          22 :           thread_local_.interrupt_flags_ &= ~flag;
     482             :         }
     483             :       }
     484             :     }
     485             :   }
     486     4381452 :   if (has_pending_interrupts(access)) set_interrupt_limits(access);
     487             :   // Remove scope from chain.
     488     4381452 :   thread_local_.interrupt_scopes_ = top->prev_;
     489     4381446 : }
     490             : 
     491             : 
     492           3 : bool StackGuard::CheckInterrupt(InterruptFlag flag) {
     493           3 :   ExecutionAccess access(isolate_);
     494           6 :   return thread_local_.interrupt_flags_ & flag;
     495             : }
     496             : 
     497             : 
     498     1072260 : void StackGuard::RequestInterrupt(InterruptFlag flag) {
     499     1072260 :   ExecutionAccess access(isolate_);
     500             :   // Check the chain of InterruptsScope for interception.
     501     1148222 :   if (thread_local_.interrupt_scopes_ &&
     502       75962 :       thread_local_.interrupt_scopes_->Intercept(flag)) {
     503     1072260 :     return;
     504             :   }
     505             : 
     506             :   // Not intercepted.  Set as active interrupt flag.
     507      996923 :   thread_local_.interrupt_flags_ |= flag;
     508      996923 :   set_interrupt_limits(access);
     509             : 
     510             :   // If this isolate is waiting in a futex, notify it to wake up.
     511      996923 :   isolate_->futex_wait_list_node()->NotifyWake();
     512             : }
     513             : 
     514             : 
     515       24949 : void StackGuard::ClearInterrupt(InterruptFlag flag) {
     516       24949 :   ExecutionAccess access(isolate_);
     517             :   // Clear the interrupt flag from the chain of InterruptsScope.
     518       47606 :   for (InterruptsScope* current = thread_local_.interrupt_scopes_;
     519             :        current != nullptr; current = current->prev_) {
     520       22657 :     current->intercepted_flags_ &= ~flag;
     521             :   }
     522             : 
     523             :   // Clear the interrupt flag from the active interrupt flags.
     524       24949 :   thread_local_.interrupt_flags_ &= ~flag;
     525       24949 :   if (!has_pending_interrupts(access)) reset_limits(access);
     526       24949 : }
     527             : 
     528             : 
     529     1214141 : bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
     530     1214141 :   ExecutionAccess access(isolate_);
     531     1214141 :   bool result = (thread_local_.interrupt_flags_ & flag);
     532     1214141 :   thread_local_.interrupt_flags_ &= ~flag;
     533     1214141 :   if (!has_pending_interrupts(access)) reset_limits(access);
     534     1214141 :   return result;
     535             : }
     536             : 
     537             : 
     538       23397 : char* StackGuard::ArchiveStackGuard(char* to) {
     539       23397 :   ExecutionAccess access(isolate_);
     540       23397 :   MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
     541             :   ThreadLocal blank;
     542             : 
     543             :   // Set the stack limits using the old thread_local_.
     544             :   // TODO(isolates): This was the old semantics of constructing a ThreadLocal
     545             :   //                 (as the ctor called SetStackLimits, which looked at the
     546             :   //                 current thread_local_ from StackGuard)-- but is this
     547             :   //                 really what was intended?
     548       23397 :   isolate_->heap()->SetStackLimits();
     549       23397 :   thread_local_ = blank;
     550             : 
     551       46794 :   return to + sizeof(ThreadLocal);
     552             : }
     553             : 
     554             : 
     555       23397 : char* StackGuard::RestoreStackGuard(char* from) {
     556       23397 :   ExecutionAccess access(isolate_);
     557       23397 :   MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
     558       23397 :   isolate_->heap()->SetStackLimits();
     559       46794 :   return from + sizeof(ThreadLocal);
     560             : }
     561             : 
     562             : 
     563        5906 : void StackGuard::FreeThreadResources() {
     564             :   Isolate::PerIsolateThreadData* per_thread =
     565        5906 :       isolate_->FindOrAllocatePerThreadDataForThisThread();
     566        5906 :   per_thread->set_stack_limit(thread_local_.real_climit_);
     567        5906 : }
     568             : 
     569             : 
     570       90352 : void StackGuard::ThreadLocal::Clear() {
     571       90352 :   real_jslimit_ = kIllegalLimit;
     572             :   set_jslimit(kIllegalLimit);
     573       90352 :   real_climit_ = kIllegalLimit;
     574             :   set_climit(kIllegalLimit);
     575       90352 :   interrupt_scopes_ = nullptr;
     576       90352 :   interrupt_flags_ = 0;
     577       90352 : }
     578             : 
     579             : 
     580       72860 : bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
     581             :   bool should_set_stack_limits = false;
     582       72860 :   if (real_climit_ == kIllegalLimit) {
     583       68217 :     const uintptr_t kLimitSize = FLAG_stack_size * KB;
     584             :     DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
     585       68217 :     uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
     586       68218 :     real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
     587             :     set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
     588       68218 :     real_climit_ = limit;
     589             :     set_climit(limit);
     590             :     should_set_stack_limits = true;
     591             :   }
     592       72861 :   interrupt_scopes_ = nullptr;
     593       72861 :   interrupt_flags_ = 0;
     594       72861 :   return should_set_stack_limits;
     595             : }
     596             : 
     597             : 
     598        5906 : void StackGuard::ClearThread(const ExecutionAccess& lock) {
     599        5906 :   thread_local_.Clear();
     600        5906 :   isolate_->heap()->SetStackLimits();
     601        5906 : }
     602             : 
     603             : 
     604       72860 : void StackGuard::InitThread(const ExecutionAccess& lock) {
     605       72860 :   if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
     606       72861 :   Isolate::PerIsolateThreadData* per_thread =
     607       72860 :       isolate_->FindOrAllocatePerThreadDataForThisThread();
     608             :   uintptr_t stored_limit = per_thread->stack_limit();
     609             :   // You should hold the ExecutionAccess lock when you call this.
     610       72861 :   if (stored_limit != 0) {
     611         190 :     SetStackLimit(stored_limit);
     612             :   }
     613       72861 : }
     614             : 
     615             : 
     616             : // --- C a l l s   t o   n a t i v e s ---
     617             : 
     618      243580 : Object StackGuard::HandleInterrupts() {
     619             :   if (FLAG_verify_predictable) {
     620             :     // Advance synthetic time by making a time request.
     621      248746 :     isolate_->heap()->MonotonicallyIncreasingTimeInMs();
     622             :   }
     623             : 
     624             :   bool any_interrupt_handled = false;
     625      243580 :   if (FLAG_trace_interrupts) {
     626           0 :     PrintF("[Handling interrupts: ");
     627             :   }
     628             : 
     629      243580 :   if (CheckAndClearInterrupt(GC_REQUEST)) {
     630       17111 :     if (FLAG_trace_interrupts) {
     631           0 :       PrintF("GC_REQUEST");
     632             :       any_interrupt_handled = true;
     633             :     }
     634       17111 :     isolate_->heap()->HandleGCRequest();
     635             :   }
     636             : 
     637      243580 :   if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
     638        1253 :     if (FLAG_trace_interrupts) {
     639           0 :       if (any_interrupt_handled) PrintF(", ");
     640           0 :       PrintF("TERMINATE_EXECUTION");
     641             :       any_interrupt_handled = true;
     642             :     }
     643        1253 :     return isolate_->TerminateExecution();
     644             :   }
     645             : 
     646      242327 :   if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
     647          35 :     if (FLAG_trace_interrupts) {
     648           0 :       if (any_interrupt_handled) PrintF(", ");
     649           0 :       PrintF("DEOPT_MARKED_ALLOCATION_SITES");
     650             :       any_interrupt_handled = true;
     651             :     }
     652          35 :     isolate_->heap()->DeoptMarkedAllocationSites();
     653             :   }
     654             : 
     655      242327 :   if (CheckAndClearInterrupt(INSTALL_CODE)) {
     656        6419 :     if (FLAG_trace_interrupts) {
     657           0 :       if (any_interrupt_handled) PrintF(", ");
     658           0 :       PrintF("INSTALL_CODE");
     659             :       any_interrupt_handled = true;
     660             :     }
     661             :     DCHECK(isolate_->concurrent_recompilation_enabled());
     662       12838 :     isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
     663             :   }
     664             : 
     665      242327 :   if (CheckAndClearInterrupt(API_INTERRUPT)) {
     666        2125 :     if (FLAG_trace_interrupts) {
     667           0 :       if (any_interrupt_handled) PrintF(", ");
     668           0 :       PrintF("API_INTERRUPT");
     669             :       any_interrupt_handled = true;
     670             :     }
     671             :     // Callbacks must be invoked outside of ExecusionAccess lock.
     672        2125 :     isolate_->InvokeApiInterruptCallbacks();
     673             :   }
     674             : 
     675      242327 :   if (FLAG_trace_interrupts) {
     676           0 :     if (!any_interrupt_handled) {
     677           0 :       PrintF("No interrupt flags set");
     678             :     }
     679           0 :     PrintF("]\n");
     680             :   }
     681             : 
     682      484654 :   isolate_->counters()->stack_interrupts()->Increment();
     683      484654 :   isolate_->counters()->runtime_profiler_ticks()->Increment();
     684      484654 :   isolate_->runtime_profiler()->MarkCandidatesForOptimization();
     685             : 
     686      484654 :   return ReadOnlyRoots(isolate_).undefined_value();
     687             : }
     688             : 
     689             : }  // namespace internal
     690      178779 : }  // namespace v8

Generated by: LCOV version 1.10