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 19 StackGuard::StackGuard() : isolate_(nullptr) {} 20 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 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 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 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 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 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 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 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 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 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 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 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 305 void StackGuard::EnableInterrupts() { 306 ExecutionAccess access(isolate_); 307 if (has_pending_interrupts(access)) { 308 set_interrupt_limits(access); 309 } 310 } 311 312 313 void StackGuard::DisableInterrupts() { 314 ExecutionAccess access(isolate_); 315 reset_limits(access); 316 } 317 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 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 371 bool StackGuard::CheckInterrupt(InterruptFlag flag) { 372 ExecutionAccess access(isolate_); 373 return thread_local_.interrupt_flags_ & flag; 374 } 375 376 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 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 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 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 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 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 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 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 477 void StackGuard::ClearThread(const ExecutionAccess& lock) { 478 thread_local_.Clear(); 479 isolate_->heap()->SetStackLimits(); 480 } 481 482 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 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