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
16namespace v8 {
17namespace internal {
18
19StackGuard::StackGuard()
20    : isolate_(NULL) {
21}
22
23
24void 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
32void 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
40static 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
56namespace {
57
58MUST_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
170MaybeHandle<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
188MaybeHandle<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
197MaybeHandle<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
204MaybeHandle<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
212MaybeHandle<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
260void 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
276void 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
289void StackGuard::EnableInterrupts() {
290  ExecutionAccess access(isolate_);
291  if (has_pending_interrupts(access)) {
292    set_interrupt_limits(access);
293  }
294}
295
296
297void StackGuard::DisableInterrupts() {
298  ExecutionAccess access(isolate_);
299  reset_limits(access);
300}
301
302
303void 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
316void 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
328bool StackGuard::CheckInterrupt(InterruptFlag flag) {
329  ExecutionAccess access(isolate_);
330  return thread_local_.interrupt_flags_ & flag;
331}
332
333
334void 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
351void 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
366bool 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
375char* 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
392char* 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
400void StackGuard::FreeThreadResources() {
401  Isolate::PerIsolateThreadData* per_thread =
402      isolate_->FindOrAllocatePerThreadDataForThisThread();
403  per_thread->set_stack_limit(thread_local_.real_climit_);
404}
405
406
407void 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
417bool 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
435void StackGuard::ClearThread(const ExecutionAccess& lock) {
436  thread_local_.Clear();
437  isolate_->heap()->SetStackLimits();
438}
439
440
441void 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
456void StackGuard::HandleGCInterrupt() {
457  if (CheckAndClearInterrupt(GC_REQUEST)) {
458    isolate_->heap()->HandleGCRequest();
459  }
460}
461
462
463Object* 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