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/isolate-inl.h" 11 #include "src/messages.h" 12 #include "src/runtime-profiler.h" 13 #include "src/vm-state-inl.h" 14 15 namespace v8 { 16 namespace internal { 17 18 StackGuard::StackGuard() 19 : isolate_(NULL) { 20 } 21 22 23 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { 24 DCHECK(isolate_ != NULL); 25 thread_local_.set_jslimit(kInterruptLimit); 26 thread_local_.set_climit(kInterruptLimit); 27 isolate_->heap()->SetStackLimits(); 28 } 29 30 31 void StackGuard::reset_limits(const ExecutionAccess& lock) { 32 DCHECK(isolate_ != NULL); 33 thread_local_.set_jslimit(thread_local_.real_jslimit_); 34 thread_local_.set_climit(thread_local_.real_climit_); 35 isolate_->heap()->SetStackLimits(); 36 } 37 38 39 static void PrintDeserializedCodeInfo(Handle<JSFunction> function) { 40 if (function->code() == function->shared()->code() && 41 function->shared()->deserialized()) { 42 PrintF("[Running deserialized script"); 43 Object* script = function->shared()->script(); 44 if (script->IsScript()) { 45 Object* name = Script::cast(script)->name(); 46 if (name->IsString()) { 47 PrintF(": %s", String::cast(name)->ToCString().get()); 48 } 49 } 50 PrintF("]\n"); 51 } 52 } 53 54 55 namespace { 56 57 MUST_USE_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, bool is_construct, 58 Handle<Object> target, 59 Handle<Object> receiver, int argc, 60 Handle<Object> args[], 61 Handle<Object> new_target) { 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 isolate->ReportPendingMessages(); 73 return MaybeHandle<Object>(); 74 } 75 #endif 76 77 // api callbacks can be called directly. 78 if (target->IsJSFunction()) { 79 Handle<JSFunction> function = Handle<JSFunction>::cast(target); 80 if ((!is_construct || function->IsConstructor()) && 81 function->shared()->IsApiFunction()) { 82 SaveContext save(isolate); 83 isolate->set_context(function->context()); 84 DCHECK(function->context()->global_object()->IsJSGlobalObject()); 85 if (is_construct) receiver = isolate->factory()->the_hole_value(); 86 auto value = Builtins::InvokeApiFunction( 87 isolate, is_construct, function, receiver, argc, args, 88 Handle<HeapObject>::cast(new_target)); 89 bool has_exception = value.is_null(); 90 DCHECK(has_exception == isolate->has_pending_exception()); 91 if (has_exception) { 92 isolate->ReportPendingMessages(); 93 return MaybeHandle<Object>(); 94 } else { 95 isolate->clear_pending_message(); 96 } 97 return value; 98 } 99 } 100 101 // Entering JavaScript. 102 VMState<JS> state(isolate); 103 CHECK(AllowJavascriptExecution::IsAllowed(isolate)); 104 if (!ThrowOnJavascriptExecution::IsAllowed(isolate)) { 105 isolate->ThrowIllegalOperation(); 106 isolate->ReportPendingMessages(); 107 return MaybeHandle<Object>(); 108 } 109 110 // Placeholder for return value. 111 Object* value = NULL; 112 113 typedef Object* (*JSEntryFunction)(Object* new_target, Object* target, 114 Object* receiver, int argc, 115 Object*** args); 116 117 Handle<Code> code = is_construct 118 ? isolate->factory()->js_construct_entry_code() 119 : isolate->factory()->js_entry_code(); 120 121 { 122 // Save and restore context around invocation and block the 123 // allocation of handles without explicit handle scopes. 124 SaveContext save(isolate); 125 SealHandleScope shs(isolate); 126 JSEntryFunction stub_entry = FUNCTION_CAST<JSEntryFunction>(code->entry()); 127 128 if (FLAG_clear_exceptions_on_js_entry) isolate->clear_pending_exception(); 129 130 // Call the function through the right JS entry stub. 131 Object* orig_func = *new_target; 132 Object* func = *target; 133 Object* recv = *receiver; 134 Object*** argv = reinterpret_cast<Object***>(args); 135 if (FLAG_profile_deserialization && target->IsJSFunction()) { 136 PrintDeserializedCodeInfo(Handle<JSFunction>::cast(target)); 137 } 138 RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::JS_Execution); 139 value = CALL_GENERATED_CODE(isolate, stub_entry, orig_func, func, recv, 140 argc, argv); 141 } 142 143 #ifdef VERIFY_HEAP 144 if (FLAG_verify_heap) { 145 value->ObjectVerify(); 146 } 147 #endif 148 149 // Update the pending exception flag and return the value. 150 bool has_exception = value->IsException(isolate); 151 DCHECK(has_exception == isolate->has_pending_exception()); 152 if (has_exception) { 153 isolate->ReportPendingMessages(); 154 return MaybeHandle<Object>(); 155 } else { 156 isolate->clear_pending_message(); 157 } 158 159 return Handle<Object>(value, isolate); 160 } 161 162 } // namespace 163 164 165 // static 166 MaybeHandle<Object> Execution::Call(Isolate* isolate, Handle<Object> callable, 167 Handle<Object> receiver, int argc, 168 Handle<Object> argv[]) { 169 // Convert calls on global objects to be calls on the global 170 // receiver instead to avoid having a 'this' pointer which refers 171 // directly to a global object. 172 if (receiver->IsJSGlobalObject()) { 173 receiver = 174 handle(Handle<JSGlobalObject>::cast(receiver)->global_proxy(), isolate); 175 } 176 return Invoke(isolate, false, callable, receiver, argc, argv, 177 isolate->factory()->undefined_value()); 178 } 179 180 181 // static 182 MaybeHandle<Object> Execution::New(Handle<JSFunction> constructor, int argc, 183 Handle<Object> argv[]) { 184 return New(constructor->GetIsolate(), constructor, constructor, argc, argv); 185 } 186 187 188 // static 189 MaybeHandle<Object> Execution::New(Isolate* isolate, Handle<Object> constructor, 190 Handle<Object> new_target, int argc, 191 Handle<Object> argv[]) { 192 return Invoke(isolate, true, constructor, 193 isolate->factory()->undefined_value(), argc, argv, new_target); 194 } 195 196 197 MaybeHandle<Object> Execution::TryCall(Isolate* isolate, 198 Handle<Object> callable, 199 Handle<Object> receiver, int argc, 200 Handle<Object> args[], 201 MaybeHandle<Object>* exception_out) { 202 bool is_termination = false; 203 MaybeHandle<Object> maybe_result; 204 if (exception_out != NULL) *exception_out = MaybeHandle<Object>(); 205 // Enter a try-block while executing the JavaScript code. To avoid 206 // duplicate error printing it must be non-verbose. Also, to avoid 207 // creating message objects during stack overflow we shouldn't 208 // capture messages. 209 { 210 v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate)); 211 catcher.SetVerbose(false); 212 catcher.SetCaptureMessage(false); 213 214 maybe_result = Call(isolate, callable, receiver, argc, args); 215 216 if (maybe_result.is_null()) { 217 DCHECK(catcher.HasCaught()); 218 DCHECK(isolate->has_pending_exception()); 219 DCHECK(isolate->external_caught_exception()); 220 if (isolate->pending_exception() == 221 isolate->heap()->termination_exception()) { 222 is_termination = true; 223 } else { 224 if (exception_out != NULL) { 225 *exception_out = v8::Utils::OpenHandle(*catcher.Exception()); 226 } 227 } 228 isolate->OptionalRescheduleException(true); 229 } 230 231 DCHECK(!isolate->has_pending_exception()); 232 } 233 234 // Re-request terminate execution interrupt to trigger later. 235 if (is_termination) isolate->stack_guard()->RequestTerminateExecution(); 236 237 return maybe_result; 238 } 239 240 241 void StackGuard::SetStackLimit(uintptr_t limit) { 242 ExecutionAccess access(isolate_); 243 // If the current limits are special (e.g. due to a pending interrupt) then 244 // leave them alone. 245 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, limit); 246 if (thread_local_.jslimit() == thread_local_.real_jslimit_) { 247 thread_local_.set_jslimit(jslimit); 248 } 249 if (thread_local_.climit() == thread_local_.real_climit_) { 250 thread_local_.set_climit(limit); 251 } 252 thread_local_.real_climit_ = limit; 253 thread_local_.real_jslimit_ = jslimit; 254 } 255 256 257 void StackGuard::AdjustStackLimitForSimulator() { 258 ExecutionAccess access(isolate_); 259 uintptr_t climit = thread_local_.real_climit_; 260 // If the current limits are special (e.g. due to a pending interrupt) then 261 // leave them alone. 262 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(isolate_, climit); 263 if (thread_local_.jslimit() == thread_local_.real_jslimit_) { 264 thread_local_.set_jslimit(jslimit); 265 isolate_->heap()->SetStackLimits(); 266 } 267 } 268 269 270 void StackGuard::EnableInterrupts() { 271 ExecutionAccess access(isolate_); 272 if (has_pending_interrupts(access)) { 273 set_interrupt_limits(access); 274 } 275 } 276 277 278 void StackGuard::DisableInterrupts() { 279 ExecutionAccess access(isolate_); 280 reset_limits(access); 281 } 282 283 284 void StackGuard::PushPostponeInterruptsScope(PostponeInterruptsScope* scope) { 285 ExecutionAccess access(isolate_); 286 // Intercept already requested interrupts. 287 int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_; 288 scope->intercepted_flags_ = intercepted; 289 thread_local_.interrupt_flags_ &= ~intercepted; 290 if (!has_pending_interrupts(access)) reset_limits(access); 291 // Add scope to the chain. 292 scope->prev_ = thread_local_.postpone_interrupts_; 293 thread_local_.postpone_interrupts_ = scope; 294 } 295 296 297 void StackGuard::PopPostponeInterruptsScope() { 298 ExecutionAccess access(isolate_); 299 PostponeInterruptsScope* top = thread_local_.postpone_interrupts_; 300 // Make intercepted interrupts active. 301 DCHECK((thread_local_.interrupt_flags_ & top->intercept_mask_) == 0); 302 thread_local_.interrupt_flags_ |= top->intercepted_flags_; 303 if (has_pending_interrupts(access)) set_interrupt_limits(access); 304 // Remove scope from chain. 305 thread_local_.postpone_interrupts_ = top->prev_; 306 } 307 308 309 bool StackGuard::CheckInterrupt(InterruptFlag flag) { 310 ExecutionAccess access(isolate_); 311 return thread_local_.interrupt_flags_ & flag; 312 } 313 314 315 void StackGuard::RequestInterrupt(InterruptFlag flag) { 316 ExecutionAccess access(isolate_); 317 // Check the chain of PostponeInterruptsScopes for interception. 318 if (thread_local_.postpone_interrupts_ && 319 thread_local_.postpone_interrupts_->Intercept(flag)) { 320 return; 321 } 322 323 // Not intercepted. Set as active interrupt flag. 324 thread_local_.interrupt_flags_ |= flag; 325 set_interrupt_limits(access); 326 327 // If this isolate is waiting in a futex, notify it to wake up. 328 isolate_->futex_wait_list_node()->NotifyWake(); 329 } 330 331 332 void StackGuard::ClearInterrupt(InterruptFlag flag) { 333 ExecutionAccess access(isolate_); 334 // Clear the interrupt flag from the chain of PostponeInterruptsScopes. 335 for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_; 336 current != NULL; 337 current = current->prev_) { 338 current->intercepted_flags_ &= ~flag; 339 } 340 341 // Clear the interrupt flag from the active interrupt flags. 342 thread_local_.interrupt_flags_ &= ~flag; 343 if (!has_pending_interrupts(access)) reset_limits(access); 344 } 345 346 347 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { 348 ExecutionAccess access(isolate_); 349 bool result = (thread_local_.interrupt_flags_ & flag); 350 thread_local_.interrupt_flags_ &= ~flag; 351 if (!has_pending_interrupts(access)) reset_limits(access); 352 return result; 353 } 354 355 356 char* StackGuard::ArchiveStackGuard(char* to) { 357 ExecutionAccess access(isolate_); 358 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); 359 ThreadLocal blank; 360 361 // Set the stack limits using the old thread_local_. 362 // TODO(isolates): This was the old semantics of constructing a ThreadLocal 363 // (as the ctor called SetStackLimits, which looked at the 364 // current thread_local_ from StackGuard)-- but is this 365 // really what was intended? 366 isolate_->heap()->SetStackLimits(); 367 thread_local_ = blank; 368 369 return to + sizeof(ThreadLocal); 370 } 371 372 373 char* StackGuard::RestoreStackGuard(char* from) { 374 ExecutionAccess access(isolate_); 375 MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); 376 isolate_->heap()->SetStackLimits(); 377 return from + sizeof(ThreadLocal); 378 } 379 380 381 void StackGuard::FreeThreadResources() { 382 Isolate::PerIsolateThreadData* per_thread = 383 isolate_->FindOrAllocatePerThreadDataForThisThread(); 384 per_thread->set_stack_limit(thread_local_.real_climit_); 385 } 386 387 388 void StackGuard::ThreadLocal::Clear() { 389 real_jslimit_ = kIllegalLimit; 390 set_jslimit(kIllegalLimit); 391 real_climit_ = kIllegalLimit; 392 set_climit(kIllegalLimit); 393 postpone_interrupts_ = NULL; 394 interrupt_flags_ = 0; 395 } 396 397 398 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { 399 bool should_set_stack_limits = false; 400 if (real_climit_ == kIllegalLimit) { 401 const uintptr_t kLimitSize = FLAG_stack_size * KB; 402 DCHECK(GetCurrentStackPosition() > kLimitSize); 403 uintptr_t limit = GetCurrentStackPosition() - kLimitSize; 404 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); 405 set_jslimit(SimulatorStack::JsLimitFromCLimit(isolate, limit)); 406 real_climit_ = limit; 407 set_climit(limit); 408 should_set_stack_limits = true; 409 } 410 postpone_interrupts_ = NULL; 411 interrupt_flags_ = 0; 412 return should_set_stack_limits; 413 } 414 415 416 void StackGuard::ClearThread(const ExecutionAccess& lock) { 417 thread_local_.Clear(); 418 isolate_->heap()->SetStackLimits(); 419 } 420 421 422 void StackGuard::InitThread(const ExecutionAccess& lock) { 423 if (thread_local_.Initialize(isolate_)) isolate_->heap()->SetStackLimits(); 424 Isolate::PerIsolateThreadData* per_thread = 425 isolate_->FindOrAllocatePerThreadDataForThisThread(); 426 uintptr_t stored_limit = per_thread->stack_limit(); 427 // You should hold the ExecutionAccess lock when you call this. 428 if (stored_limit != 0) { 429 SetStackLimit(stored_limit); 430 } 431 } 432 433 434 // --- C a l l s t o n a t i v e s --- 435 436 437 void StackGuard::HandleGCInterrupt() { 438 if (CheckAndClearInterrupt(GC_REQUEST)) { 439 isolate_->heap()->HandleGCRequest(); 440 } 441 } 442 443 444 Object* StackGuard::HandleInterrupts() { 445 if (FLAG_verify_predictable) { 446 // Advance synthetic time by making a time request. 447 isolate_->heap()->MonotonicallyIncreasingTimeInMs(); 448 } 449 450 if (CheckAndClearInterrupt(GC_REQUEST)) { 451 isolate_->heap()->HandleGCRequest(); 452 } 453 454 if (CheckDebugBreak() || CheckDebugCommand()) { 455 isolate_->debug()->HandleDebugBreak(); 456 } 457 458 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { 459 return isolate_->TerminateExecution(); 460 } 461 462 if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES)) { 463 isolate_->heap()->DeoptMarkedAllocationSites(); 464 } 465 466 if (CheckAndClearInterrupt(INSTALL_CODE)) { 467 DCHECK(isolate_->concurrent_recompilation_enabled()); 468 isolate_->optimizing_compile_dispatcher()->InstallOptimizedFunctions(); 469 } 470 471 if (CheckAndClearInterrupt(API_INTERRUPT)) { 472 // Callbacks must be invoked outside of ExecusionAccess lock. 473 isolate_->InvokeApiInterruptCallbacks(); 474 } 475 476 isolate_->counters()->stack_interrupts()->Increment(); 477 isolate_->counters()->runtime_profiler_ticks()->Increment(); 478 isolate_->runtime_profiler()->MarkCandidatesForOptimization(); 479 480 return isolate_->heap()->undefined_value(); 481 } 482 483 } // namespace internal 484 } // namespace v8 485