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