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