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