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