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