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