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