Home | History | Annotate | Download | only in src
      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/messages.h"
     13 #include "src/runtime-profiler.h"
     14 #include "src/vm-state-inl.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 StackGuard::StackGuard() : isolate_(nullptr) {}
     20 
     21 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
     22   DCHECK_NOT_NULL(isolate_);
     23   thread_local_.set_jslimit(kInterruptLimit);
     24   thread_local_.set_climit(kInterruptLimit);
     25   isolate_->heap()->SetStackLimits();
     26 }
     27 
     28 
     29 void StackGuard::reset_limits(const ExecutionAccess& lock) {
     30   DCHECK_NOT_NULL(isolate_);
     31   thread_local_.set_jslimit(thread_local_.real_jslimit_);
     32   thread_local_.set_climit(thread_local_.real_climit_);
     33   isolate_->heap()->SetStackLimits();
     34 }
     35 
     36 
     37 static void PrintDeserializedCodeInfo(Handle<JSFunction> function) {
     38   if (function->code() == function->shared()->GetCode() &&
     39       function->shared()->deserialized()) {
     40     PrintF("[Running deserialized script");
     41     Object* script = function->shared()->script();
     42     if (script->IsScript()) {
     43       Object* name = Script::cast(script)->name();
     44       if (name->IsString()) {
     45         PrintF(": %s", String::cast(name)->ToCString().get());
     46       }
     47     }
     48     PrintF("]\n");
     49   }
     50 }
     51 
     52 
     53 namespace {
     54 
     55 V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(
     56     Isolate* isolate, bool is_construct, Handle<Object> target,
     57     Handle<Object> receiver, int argc, Handle<Object> args[],
     58     Handle<Object> new_target, Execution::MessageHandling message_handling,
     59     Execution::Target execution_target) {
     60   DCHECK(!receiver->IsJSGlobalObject());
     61 
     62 #ifdef USE_SIMULATOR
     63   // Simulators use separate stacks for C++ and JS. JS stack overflow checks
     64   // are performed whenever a JS function is called. However, it can be the case
     65   // that the C++ stack grows faster than the JS stack, resulting in an overflow
     66   // there. Add a check here to make that less likely.
     67   StackLimitCheck check(isolate);
     68   if (check.HasOverflowed()) {
     69     isolate->StackOverflow();
     70     if (message_handling == Execution::MessageHandling::kReport) {
     71       isolate->ReportPendingMessages();
     72     }
     73     return MaybeHandle<Object>();
     74   }
     75 #endif
     76 
     77   // api callbacks can be called directly, unless we want to take the detour
     78   // through JS to set up a frame for break-at-entry.
     79   if (target->IsJSFunction()) {
     80     Handle<JSFunction> function = Handle<JSFunction>::cast(target);
     81     if ((!is_construct || function->IsConstructor()) &&
     82         function->shared()->IsApiFunction() &&
     83         !function->shared()->BreakAtEntry()) {
     84       SaveContext save(isolate);
     85       isolate->set_context(function->context());
     86       DCHECK(function->context()->global_object()->IsJSGlobalObject());
     87       if (is_construct) receiver = isolate->factory()->the_hole_value();
     88       auto value = Builtins::InvokeApiFunction(
     89           isolate, is_construct, function, receiver, argc, args,
     90           Handle<HeapObject>::cast(new_target));
     91       bool has_exception = value.is_null();
     92       DCHECK(has_exception == isolate->has_pending_exception());
     93       if (has_exception) {
     94         if (message_handling == Execution::MessageHandling::kReport) {
     95           isolate->ReportPendingMessages();
     96         }
     97         return MaybeHandle<Object>();
     98       } else {
     99         isolate->clear_pending_message();
    100       }
    101       return value;
    102     }
    103   }
    104 
    105   // Entering JavaScript.
    106   VMState<JS> state(isolate);
    107   CHECK(AllowJavascriptExecution::IsAllowed(isolate));
    108   if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) {
    109     isolate->ThrowIllegalOperation();
    110     if (message_handling == Execution::MessageHandling::kReport) {
    111       isolate->ReportPendingMessages();
    112     }
    113     return MaybeHandle<Object>();
    114   }
    115 
    116   // Placeholder for return value.
    117   Object* value = nullptr;
    118 
    119   using JSEntryFunction =
    120       GeneratedCode<Object*(Object * new_target, Object * target,
    121                             Object * receiver, int argc, Object*** args)>;
    122 
    123   Handle<Code> code;
    124   switch (execution_target) {
    125     case Execution::Target::kCallable:
    126       code = is_construct ? isolate->factory()->js_construct_entry_code()
    127                           : isolate->factory()->js_entry_code();
    128       break;
    129     case Execution::Target::kRunMicrotasks:
    130       code = isolate->factory()->js_run_microtasks_entry_code();
    131       break;
    132     default:
    133       UNREACHABLE();
    134   }
    135 
    136   {
    137     // Save and restore context around invocation and block the
    138     // allocation of handles without explicit handle scopes.
    139     SaveContext save(isolate);
    140     SealHandleScope shs(isolate);
    141     JSEntryFunction stub_entry =
    142         JSEntryFunction::FromAddress(isolate, code->entry());
    143 
    144     if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception();
    145 
    146     // Call the function through the right JS entry stub.
    147     Object* orig_func = *new_target;
    148     Object* func = *target;
    149     Object* recv = *receiver;
    150     Object*** argv = reinterpret_cast<Object***>(args);
    151     if (FLAG_profile_deserialization && target->IsJSFunction()) {
    152       PrintDeserializedCodeInfo(Handle<JSFunction>::cast(target));
    153     }
    154     RuntimeCallTimerScope timer(isolate, RuntimeCallCounterId::kJS_Execution);
    155     value = stub_entry.Call(orig_func, func, recv, argc, argv);
    156   }
    157 
    158 #ifdef VERIFY_HEAP
    159   if (FLAG_verify_heap) {
    160     value->ObjectVerify(isolate);
    161   }
    162 #endif
    163 
    164   // Update the pending exception flag and return the value.
    165   bool has_exception = value->IsException(isolate);
    166   DCHECK(has_exception == isolate->has_pending_exception());
    167   if (has_exception) {
    168     if (message_handling == Execution::MessageHandling::kReport) {
    169       isolate->ReportPendingMessages();
    170     }
    171     return MaybeHandle<Object>();
    172   } else {
    173     isolate->clear_pending_message();
    174   }
    175 
    176   return Handle<Object>(value, isolate);
    177 }
    178 
    179 MaybeHandle<Object> CallInternal(Isolate* isolate, Handle<Object> callable,
    180                                  Handle<Object> receiver, int argc,
    181                                  Handle<Object> argv[],
    182                                  Execution::MessageHandling message_handling,
    183                                  Execution::Target target) {
    184   // Convert calls on global objects to be calls on the global
    185   // receiver instead to avoid having a 'this' pointer which refers
    186   // directly to a global object.
    187   if (receiver->IsJSGlobalObject()) {
    188     receiver =
    189         handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate);
    190   }
    191   return Invoke(isolate, false, callable, receiver, argc, argv,
    192                 isolate->factory()->undefined_value(), message_handling,
    193                 target);
    194 }
    195 
    196 }  // namespace
    197 
    198 // static
    199 MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable,
    200                                     Handle<Object> receiver, int argc,
    201                                     Handle<Object> argv[]) {
    202   return CallInternal(isolate, callable, receiver, argc, argv,
    203                       MessageHandling::kReport, Execution::Target::kCallable);
    204 }
    205 
    206 
    207 // static
    208 MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
    209                                    int argc, Handle<Object> argv[]) {
    210   return New(isolate, constructor, constructor, argc, argv);
    211 }
    212 
    213 
    214 // static
    215 MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor,
    216                                    Handle<Object> new_target, int argc,
    217                                    Handle<Object> argv[]) {
    218   return Invoke(isolate, true, constructor,
    219                 isolate->factory()->undefined_value(), argc, argv, new_target,
    220                 MessageHandling::kReport, Execution::Target::kCallable);
    221 }
    222 
    223 MaybeHandle<Object> Execution::TryCall(
    224     Isolate* isolate, Handle<Object> callable, Handle<Object> receiver,
    225     int argc, Handle<Object> args[], MessageHandling message_handling,
    226     MaybeHandle<Object>* exception_out, Target target) {
    227   bool is_termination = false;
    228   MaybeHandle<Object> maybe_result;
    229   if (exception_out != nullptr) *exception_out = MaybeHandle<Object>();
    230   DCHECK_IMPLIES(message_handling == MessageHandling::kKeepPending,
    231                  exception_out == nullptr);
    232   // Enter a try-block while executing the JavaScript code. To avoid
    233   // duplicate error printing it must be non-verbose.  Also, to avoid
    234   // creating message objects during stack overflow we shouldn't
    235   // capture messages.
    236   {
    237     v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
    238     catcher.SetVerbose(false);
    239     catcher.SetCaptureMessage(false);
    240 
    241     maybe_result = CallInternal(isolate, callable, receiver, argc, args,
    242                                 message_handling, target);
    243 
    244     if (maybe_result.is_null()) {
    245       DCHECK(isolate->has_pending_exception());
    246       if (isolate->pending_exception() ==
    247           ReadOnlyRoots(isolate).termination_exception()) {
    248         is_termination = true;
    249       } else {
    250         if (exception_out != nullptr) {
    251           DCHECK(catcher.HasCaught());
    252           DCHECK(isolate->external_caught_exception());
    253           *exception_out = v8::Utils::OpenHandle(*catcher.Exception());
    254         }
    255       }
    256       if (message_handling == MessageHandling::kReport) {
    257         isolate->OptionalRescheduleException(true);
    258       }
    259     }
    260   }
    261 
    262   // Re-request terminate execution interrupt to trigger later.
    263   if (is_termination) isolate->stack_guard()->RequestTerminateExecution();
    264 
    265   return maybe_result;
    266 }
    267 
    268 MaybeHandle<Object> Execution::RunMicrotasks(
    269     Isolate* isolate, MessageHandling message_handling,
    270     MaybeHandle<Object>* exception_out) {
    271   auto undefined = isolate->factory()->undefined_value();
    272   return TryCall(isolate, undefined, undefined, 0, {}, message_handling,
    273                  exception_out, Target::kRunMicrotasks);
    274 }
    275 
    276 void StackGuard::SetStackLimit(uintptr_t limit) {
    277   ExecutionAccess access(isolate_);
    278   // If the current limits are special (e.g. due to a pending interrupt) then
    279   // leave them alone.
    280   uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit);
    281   if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
    282     thread_local_.set_jslimit(jslimit);
    283   }
    284   if (thread_local_.climit() == thread_local_.real_climit_) {
    285     thread_local_.set_climit(limit);
    286   }
    287   thread_local_.real_climit_ = limit;
    288   thread_local_.real_jslimit_ = jslimit;
    289 }
    290 
    291 
    292 void StackGuard::AdjustStackLimitForSimulator() {
    293   ExecutionAccess access(isolate_);
    294   uintptr_t climit = thread_local_.real_climit_;
    295   // If the current limits are special (e.g. due to a pending interrupt) then
    296   // leave them alone.
    297   uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit);
    298   if (thread_local_.jslimit() == thread_local_.real_jslimit_) {
    299     thread_local_.set_jslimit(jslimit);
    300     isolate_->heap()->SetStackLimits();
    301   }
    302 }
    303 
    304 
    305 void StackGuard::EnableInterrupts() {
    306   ExecutionAccess access(isolate_);
    307   if (has_pending_interrupts(access)) {
    308     set_interrupt_limits(access);
    309   }
    310 }
    311 
    312 
    313 void StackGuard::DisableInterrupts() {
    314   ExecutionAccess access(isolate_);
    315   reset_limits(access);
    316 }
    317 
    318 void StackGuard::PushInterruptsScope(InterruptsScope* scope) {
    319   ExecutionAccess access(isolate_);
    320   DCHECK_NE(scope->mode_, InterruptsScope::kNoop);
    321   if (scope->mode_ == InterruptsScope::kPostponeInterrupts) {
    322     // Intercept already requested interrupts.
    323     int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_;
    324     scope->intercepted_flags_ = intercepted;
    325     thread_local_.interrupt_flags_ &= ~intercepted;
    326   } else {
    327     DCHECK_EQ(scope->mode_, InterruptsScope::kRunInterrupts);
    328     // Restore postponed interrupts.
    329     int restored_flags = 0;
    330     for (InterruptsScope* current = thread_local_.interrupt_scopes_;
    331          current != nullptr; current = current->prev_) {
    332       restored_flags |= (current->intercepted_flags_ & scope->intercept_mask_);
    333       current->intercepted_flags_ &= ~scope->intercept_mask_;
    334     }
    335     thread_local_.interrupt_flags_ |= restored_flags;
    336   }
    337   if (!has_pending_interrupts(access)) reset_limits(access);
    338   // Add scope to the chain.
    339   scope->prev_ = thread_local_.interrupt_scopes_;
    340   thread_local_.interrupt_scopes_ = scope;
    341 }
    342 
    343 void StackGuard::PopInterruptsScope() {
    344   ExecutionAccess access(isolate_);
    345   InterruptsScope* top = thread_local_.interrupt_scopes_;
    346   DCHECK_NE(top->mode_, InterruptsScope::kNoop);
    347   if (top->mode_ == InterruptsScope::kPostponeInterrupts) {
    348     // Make intercepted interrupts active.
    349     DCHECK_EQ(thread_local_.interrupt_flags_ & top->intercept_mask_, 0);
    350     thread_local_.interrupt_flags_ |= top->intercepted_flags_;
    351   } else {
    352     DCHECK_EQ(top->mode_, InterruptsScope::kRunInterrupts);
    353     // Postpone existing interupts if needed.
    354     if (top->prev_) {
    355       for (int interrupt = 1; interrupt < ALL_INTERRUPTS;
    356            interrupt = interrupt << 1) {
    357         InterruptFlag flag = static_cast<InterruptFlag>(interrupt);
    358         if ((thread_local_.interrupt_flags_ & flag) &&
    359             top->prev_->Intercept(flag)) {
    360           thread_local_.interrupt_flags_ &= ~flag;
    361         }
    362       }
    363     }
    364   }
    365   if (has_pending_interrupts(access)) set_interrupt_limits(access);
    366   // Remove scope from chain.
    367   thread_local_.interrupt_scopes_ = top->prev_;
    368 }
    369 
    370 
    371 bool StackGuard::CheckInterrupt(InterruptFlag flag) {
    372   ExecutionAccess access(isolate_);
    373   return thread_local_.interrupt_flags_ & flag;
    374 }
    375 
    376 
    377 void StackGuard::RequestInterrupt(InterruptFlag flag) {
    378   ExecutionAccess access(isolate_);
    379   // Check the chain of InterruptsScope for interception.
    380   if (thread_local_.interrupt_scopes_ &&
    381       thread_local_.interrupt_scopes_->Intercept(flag)) {
    382     return;
    383   }
    384 
    385   // Not intercepted.  Set as active interrupt flag.
    386   thread_local_.interrupt_flags_ |= flag;
    387   set_interrupt_limits(access);
    388 
    389   // If this isolate is waiting in a futex, notify it to wake up.
    390   isolate_->futex_wait_list_node()->NotifyWake();
    391 }
    392 
    393 
    394 void StackGuard::ClearInterrupt(InterruptFlag flag) {
    395   ExecutionAccess access(isolate_);
    396   // Clear the interrupt flag from the chain of InterruptsScope.
    397   for (InterruptsScope* current = thread_local_.interrupt_scopes_;
    398        current != nullptr; current = current->prev_) {
    399     current->intercepted_flags_ &= ~flag;
    400   }
    401 
    402   // Clear the interrupt flag from the active interrupt flags.
    403   thread_local_.interrupt_flags_ &= ~flag;
    404   if (!has_pending_interrupts(access)) reset_limits(access);
    405 }
    406 
    407 
    408 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
    409   ExecutionAccess access(isolate_);
    410   bool result = (thread_local_.interrupt_flags_ & flag);
    411   thread_local_.interrupt_flags_ &= ~flag;
    412   if (!has_pending_interrupts(access)) reset_limits(access);
    413   return result;
    414 }
    415 
    416 
    417 char* StackGuard::ArchiveStackGuard(char* to) {
    418   ExecutionAccess access(isolate_);
    419   MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
    420   ThreadLocal blank;
    421 
    422   // Set the stack limits using the old thread_local_.
    423   // TODO(isolates): This was the old semantics of constructing a ThreadLocal
    424   //                 (as the ctor called SetStackLimits, which looked at the
    425   //                 current thread_local_ from StackGuard)-- but is this
    426   //                 really what was intended?
    427   isolate_->heap()->SetStackLimits();
    428   thread_local_ = blank;
    429 
    430   return to + sizeof(ThreadLocal);
    431 }
    432 
    433 
    434 char* StackGuard::RestoreStackGuard(char* from) {
    435   ExecutionAccess access(isolate_);
    436   MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
    437   isolate_->heap()->SetStackLimits();
    438   return from + sizeof(ThreadLocal);
    439 }
    440 
    441 
    442 void StackGuard::FreeThreadResources() {
    443   Isolate::PerIsolateThreadData* per_thread =
    444       isolate_->FindOrAllocatePerThreadDataForThisThread();
    445   per_thread->set_stack_limit(thread_local_.real_climit_);
    446 }
    447 
    448 
    449 void StackGuard::ThreadLocal::Clear() {
    450   real_jslimit_ = kIllegalLimit;
    451   set_jslimit(kIllegalLimit);
    452   real_climit_ = kIllegalLimit;
    453   set_climit(kIllegalLimit);
    454   interrupt_scopes_ = nullptr;
    455   interrupt_flags_ = 0;
    456 }
    457 
    458 
    459 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
    460   bool should_set_stack_limits = false;
    461   if (real_climit_ == kIllegalLimit) {
    462     const uintptr_t kLimitSize = FLAG_stack_size * KB;
    463     DCHECK_GT(GetCurrentStackPosition(), kLimitSize);
    464     uintptr_t limit = GetCurrentStackPosition() - kLimitSize;
    465     real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
    466     set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit));
    467     real_climit_ = limit;
    468     set_climit(limit);
    469     should_set_stack_limits = true;
    470   }
    471   interrupt_scopes_ = nullptr;
    472   interrupt_flags_ = 0;
    473   return should_set_stack_limits;
    474 }
    475 
    476 
    477 void StackGuard::ClearThread(const ExecutionAccess& lock) {
    478   thread_local_.Clear();
    479   isolate_->heap()->SetStackLimits();
    480 }
    481 
    482 
    483 void StackGuard::InitThread(const ExecutionAccess& lock) {
    484   if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits();
    485   Isolate::PerIsolateThreadData* per_thread =
    486       isolate_->FindOrAllocatePerThreadDataForThisThread();
    487   uintptr_t stored_limit = per_thread->stack_limit();
    488   // You should hold the ExecutionAccess lock when you call this.
    489   if (stored_limit != 0) {
    490     SetStackLimit(stored_limit);
    491   }
    492 }
    493 
    494 
    495 // --- C a l l s   t o   n a t i v e s ---
    496 
    497 
    498 Object* StackGuard::HandleInterrupts() {
    499   if (FLAG_verify_predictable) {
    500     // Advance synthetic time by making a time request.
    501     isolate_->heap()->MonotonicallyIncreasingTimeInMs();
    502   }
    503 
    504   bool any_interrupt_handled = false;
    505   if (FLAG_trace_interrupts) {
    506     PrintF("[Handling interrupts: ");
    507   }
    508 
    509   if (CheckAndClearInterrupt(GC_REQUEST)) {
    510     if (FLAG_trace_interrupts) {
    511       PrintF("GC_REQUEST");
    512       any_interrupt_handled = true;
    513     }
    514     isolate_->heap()->HandleGCRequest();
    515   }
    516 
    517   if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) {
    518     if (FLAG_trace_interrupts) {
    519       if (any_interrupt_handled) PrintF(", ");
    520       PrintF("TERMINATE_EXECUTION");
    521       any_interrupt_handled = true;
    522     }
    523     return isolate_->TerminateExecution();
    524   }
    525 
    526   if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) {
    527     if (FLAG_trace_interrupts) {
    528       if (any_interrupt_handled) PrintF(", ");
    529       PrintF("DEOPT_MARKED_ALLOCATION_SITES");
    530       any_interrupt_handled = true;
    531     }
    532     isolate_->heap()->DeoptMarkedAllocationSites();
    533   }
    534 
    535   if (CheckAndClearInterrupt(INSTALL_CODE)) {
    536     if (FLAG_trace_interrupts) {
    537       if (any_interrupt_handled) PrintF(", ");
    538       PrintF("INSTALL_CODE");
    539       any_interrupt_handled = true;
    540     }
    541     DCHECK(isolate_->concurrent_recompilation_enabled());
    542     isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
    543   }
    544 
    545   if (CheckAndClearInterrupt(API_INTERRUPT)) {
    546     if (FLAG_trace_interrupts) {
    547       if (any_interrupt_handled) PrintF(", ");
    548       PrintF("API_INTERRUPT");
    549       any_interrupt_handled = true;
    550     }
    551     // Callbacks must be invoked outside of ExecusionAccess lock.
    552     isolate_->InvokeApiInterruptCallbacks();
    553   }
    554 
    555   if (FLAG_trace_interrupts) {
    556     if (!any_interrupt_handled) {
    557       PrintF("No interrupt flags set");
    558     }
    559     PrintF("]\n");
    560   }
    561 
    562   isolate_->counters()->stack_interrupts()->Increment();
    563   isolate_->counters()->runtime_profiler_ticks()->Increment();
    564   isolate_->runtime_profiler()->MarkCandidatesForOptimization();
    565 
    566   return ReadOnlyRoots(isolate_).undefined_value();
    567 }
    568 
    569 }  // namespace internal
    570 }  // namespace v8
    571