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