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