execution.cc revision 44f0eee88ff00398ff7f715fab053374d808c90d
1// Copyright 2006-2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <stdlib.h> 29 30#include "v8.h" 31 32#include "api.h" 33#include "bootstrapper.h" 34#include "codegen-inl.h" 35#include "debug.h" 36#include "runtime-profiler.h" 37#include "simulator.h" 38#include "v8threads.h" 39#include "vm-state-inl.h" 40 41namespace v8 { 42namespace internal { 43 44 45StackGuard::StackGuard() 46 : isolate_(NULL) { 47} 48 49 50void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { 51 ASSERT(isolate_ != NULL); 52 // Ignore attempts to interrupt when interrupts are postponed. 53 if (should_postpone_interrupts(lock)) return; 54 thread_local_.jslimit_ = kInterruptLimit; 55 thread_local_.climit_ = kInterruptLimit; 56 isolate_->heap()->SetStackLimits(); 57} 58 59 60void StackGuard::reset_limits(const ExecutionAccess& lock) { 61 ASSERT(isolate_ != NULL); 62 thread_local_.jslimit_ = thread_local_.real_jslimit_; 63 thread_local_.climit_ = thread_local_.real_climit_; 64 isolate_->heap()->SetStackLimits(); 65} 66 67 68static Handle<Object> Invoke(bool construct, 69 Handle<JSFunction> func, 70 Handle<Object> receiver, 71 int argc, 72 Object*** args, 73 bool* has_pending_exception) { 74 Isolate* isolate = func->GetIsolate(); 75 76 // Entering JavaScript. 77 VMState state(isolate, JS); 78 79 // Placeholder for return value. 80 MaybeObject* value = reinterpret_cast<Object*>(kZapValue); 81 82 typedef Object* (*JSEntryFunction)( 83 byte* entry, 84 Object* function, 85 Object* receiver, 86 int argc, 87 Object*** args); 88 89 Handle<Code> code; 90 if (construct) { 91 JSConstructEntryStub stub; 92 code = stub.GetCode(); 93 } else { 94 JSEntryStub stub; 95 code = stub.GetCode(); 96 } 97 98 // Convert calls on global objects to be calls on the global 99 // receiver instead to avoid having a 'this' pointer which refers 100 // directly to a global object. 101 if (receiver->IsGlobalObject()) { 102 Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); 103 receiver = Handle<JSObject>(global->global_receiver()); 104 } 105 106 // Make sure that the global object of the context we're about to 107 // make the current one is indeed a global object. 108 ASSERT(func->context()->global()->IsGlobalObject()); 109 110 { 111 // Save and restore context around invocation and block the 112 // allocation of handles without explicit handle scopes. 113 SaveContext save(isolate); 114 NoHandleAllocation na; 115 JSEntryFunction entry = FUNCTION_CAST<JSEntryFunction>(code->entry()); 116 117 // Call the function through the right JS entry stub. 118 byte* entry_address = func->code()->entry(); 119 JSFunction* function = *func; 120 Object* receiver_pointer = *receiver; 121 value = CALL_GENERATED_CODE(entry, entry_address, function, 122 receiver_pointer, argc, args); 123 } 124 125#ifdef DEBUG 126 value->Verify(); 127#endif 128 129 // Update the pending exception flag and return the value. 130 *has_pending_exception = value->IsException(); 131 ASSERT(*has_pending_exception == Isolate::Current()->has_pending_exception()); 132 if (*has_pending_exception) { 133 isolate->ReportPendingMessages(); 134 if (isolate->pending_exception() == Failure::OutOfMemoryException()) { 135 if (!isolate->handle_scope_implementer()->ignore_out_of_memory()) { 136 V8::FatalProcessOutOfMemory("JS", true); 137 } 138 } 139 return Handle<Object>(); 140 } else { 141 isolate->clear_pending_message(); 142 } 143 144 return Handle<Object>(value->ToObjectUnchecked(), isolate); 145} 146 147 148Handle<Object> Execution::Call(Handle<JSFunction> func, 149 Handle<Object> receiver, 150 int argc, 151 Object*** args, 152 bool* pending_exception) { 153 return Invoke(false, func, receiver, argc, args, pending_exception); 154} 155 156 157Handle<Object> Execution::New(Handle<JSFunction> func, int argc, 158 Object*** args, bool* pending_exception) { 159 return Invoke(true, func, Isolate::Current()->global(), argc, args, 160 pending_exception); 161} 162 163 164Handle<Object> Execution::TryCall(Handle<JSFunction> func, 165 Handle<Object> receiver, 166 int argc, 167 Object*** args, 168 bool* caught_exception) { 169 // Enter a try-block while executing the JavaScript code. To avoid 170 // duplicate error printing it must be non-verbose. Also, to avoid 171 // creating message objects during stack overflow we shouldn't 172 // capture messages. 173 v8::TryCatch catcher; 174 catcher.SetVerbose(false); 175 catcher.SetCaptureMessage(false); 176 177 Handle<Object> result = Invoke(false, func, receiver, argc, args, 178 caught_exception); 179 180 if (*caught_exception) { 181 ASSERT(catcher.HasCaught()); 182 Isolate* isolate = Isolate::Current(); 183 ASSERT(isolate->has_pending_exception()); 184 ASSERT(isolate->external_caught_exception()); 185 if (isolate->pending_exception() == 186 isolate->heap()->termination_exception()) { 187 result = isolate->factory()->termination_exception(); 188 } else { 189 result = v8::Utils::OpenHandle(*catcher.Exception()); 190 } 191 isolate->OptionalRescheduleException(true); 192 } 193 194 ASSERT(!Isolate::Current()->has_pending_exception()); 195 ASSERT(!Isolate::Current()->external_caught_exception()); 196 return result; 197} 198 199 200Handle<Object> Execution::GetFunctionDelegate(Handle<Object> object) { 201 ASSERT(!object->IsJSFunction()); 202 203 // If you return a function from here, it will be called when an 204 // attempt is made to call the given object as a function. 205 206 // Regular expressions can be called as functions in both Firefox 207 // and Safari so we allow it too. 208 if (object->IsJSRegExp()) { 209 Handle<String> exec = FACTORY->exec_symbol(); 210 // TODO(lrn): Bug 617. We should use the default function here, not the 211 // one on the RegExp object. 212 Object* exec_function; 213 { MaybeObject* maybe_exec_function = object->GetProperty(*exec); 214 // This can lose an exception, but the alternative is to put a failure 215 // object in a handle, which is not GC safe. 216 if (!maybe_exec_function->ToObject(&exec_function)) { 217 return FACTORY->undefined_value(); 218 } 219 } 220 return Handle<Object>(exec_function); 221 } 222 223 // Objects created through the API can have an instance-call handler 224 // that should be used when calling the object as a function. 225 if (object->IsHeapObject() && 226 HeapObject::cast(*object)->map()->has_instance_call_handler()) { 227 return Handle<JSFunction>( 228 Isolate::Current()->global_context()->call_as_function_delegate()); 229 } 230 231 return FACTORY->undefined_value(); 232} 233 234 235Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) { 236 ASSERT(!object->IsJSFunction()); 237 238 // If you return a function from here, it will be called when an 239 // attempt is made to call the given object as a constructor. 240 241 // Objects created through the API can have an instance-call handler 242 // that should be used when calling the object as a function. 243 if (object->IsHeapObject() && 244 HeapObject::cast(*object)->map()->has_instance_call_handler()) { 245 return Handle<JSFunction>( 246 Isolate::Current()->global_context()->call_as_constructor_delegate()); 247 } 248 249 return FACTORY->undefined_value(); 250} 251 252 253bool StackGuard::IsStackOverflow() { 254 ExecutionAccess access(isolate_); 255 return (thread_local_.jslimit_ != kInterruptLimit && 256 thread_local_.climit_ != kInterruptLimit); 257} 258 259 260void StackGuard::EnableInterrupts() { 261 ExecutionAccess access(isolate_); 262 if (has_pending_interrupts(access)) { 263 set_interrupt_limits(access); 264 } 265} 266 267 268void StackGuard::SetStackLimit(uintptr_t limit) { 269 ExecutionAccess access(isolate_); 270 // If the current limits are special (eg due to a pending interrupt) then 271 // leave them alone. 272 uintptr_t jslimit = SimulatorStack::JsLimitFromCLimit(limit); 273 if (thread_local_.jslimit_ == thread_local_.real_jslimit_) { 274 thread_local_.jslimit_ = jslimit; 275 } 276 if (thread_local_.climit_ == thread_local_.real_climit_) { 277 thread_local_.climit_ = limit; 278 } 279 thread_local_.real_climit_ = limit; 280 thread_local_.real_jslimit_ = jslimit; 281} 282 283 284void StackGuard::DisableInterrupts() { 285 ExecutionAccess access(isolate_); 286 reset_limits(access); 287} 288 289 290bool StackGuard::IsInterrupted() { 291 ExecutionAccess access(isolate_); 292 return thread_local_.interrupt_flags_ & INTERRUPT; 293} 294 295 296void StackGuard::Interrupt() { 297 ExecutionAccess access(isolate_); 298 thread_local_.interrupt_flags_ |= INTERRUPT; 299 set_interrupt_limits(access); 300} 301 302 303bool StackGuard::IsPreempted() { 304 ExecutionAccess access(isolate_); 305 return thread_local_.interrupt_flags_ & PREEMPT; 306} 307 308 309void StackGuard::Preempt() { 310 ExecutionAccess access(isolate_); 311 thread_local_.interrupt_flags_ |= PREEMPT; 312 set_interrupt_limits(access); 313} 314 315 316bool StackGuard::IsTerminateExecution() { 317 ExecutionAccess access(isolate_); 318 return thread_local_.interrupt_flags_ & TERMINATE; 319} 320 321 322void StackGuard::TerminateExecution() { 323 ExecutionAccess access(isolate_); 324 thread_local_.interrupt_flags_ |= TERMINATE; 325 set_interrupt_limits(access); 326} 327 328 329bool StackGuard::IsRuntimeProfilerTick() { 330 ExecutionAccess access(isolate_); 331 return thread_local_.interrupt_flags_ & RUNTIME_PROFILER_TICK; 332} 333 334 335void StackGuard::RequestRuntimeProfilerTick() { 336 // Ignore calls if we're not optimizing or if we can't get the lock. 337 if (FLAG_opt && ExecutionAccess::TryLock(isolate_)) { 338 thread_local_.interrupt_flags_ |= RUNTIME_PROFILER_TICK; 339 if (thread_local_.postpone_interrupts_nesting_ == 0) { 340 thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit; 341 isolate_->heap()->SetStackLimits(); 342 } 343 ExecutionAccess::Unlock(isolate_); 344 } 345} 346 347 348#ifdef ENABLE_DEBUGGER_SUPPORT 349bool StackGuard::IsDebugBreak() { 350 ExecutionAccess access(isolate_); 351 return thread_local_.interrupt_flags_ & DEBUGBREAK; 352} 353 354 355void StackGuard::DebugBreak() { 356 ExecutionAccess access(isolate_); 357 thread_local_.interrupt_flags_ |= DEBUGBREAK; 358 set_interrupt_limits(access); 359} 360 361 362bool StackGuard::IsDebugCommand() { 363 ExecutionAccess access(isolate_); 364 return thread_local_.interrupt_flags_ & DEBUGCOMMAND; 365} 366 367 368void StackGuard::DebugCommand() { 369 if (FLAG_debugger_auto_break) { 370 ExecutionAccess access(isolate_); 371 thread_local_.interrupt_flags_ |= DEBUGCOMMAND; 372 set_interrupt_limits(access); 373 } 374} 375#endif 376 377void StackGuard::Continue(InterruptFlag after_what) { 378 ExecutionAccess access(isolate_); 379 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what); 380 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { 381 reset_limits(access); 382 } 383} 384 385 386char* StackGuard::ArchiveStackGuard(char* to) { 387 ExecutionAccess access(isolate_); 388 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); 389 ThreadLocal blank; 390 391 // Set the stack limits using the old thread_local_. 392 // TODO(isolates): This was the old semantics of constructing a ThreadLocal 393 // (as the ctor called SetStackLimits, which looked at the 394 // current thread_local_ from StackGuard)-- but is this 395 // really what was intended? 396 isolate_->heap()->SetStackLimits(); 397 thread_local_ = blank; 398 399 return to + sizeof(ThreadLocal); 400} 401 402 403char* StackGuard::RestoreStackGuard(char* from) { 404 ExecutionAccess access(isolate_); 405 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); 406 isolate_->heap()->SetStackLimits(); 407 return from + sizeof(ThreadLocal); 408} 409 410 411void StackGuard::FreeThreadResources() { 412 Isolate::CurrentPerIsolateThreadData()->set_stack_limit( 413 thread_local_.real_climit_); 414} 415 416 417void StackGuard::ThreadLocal::Clear() { 418 real_jslimit_ = kIllegalLimit; 419 jslimit_ = kIllegalLimit; 420 real_climit_ = kIllegalLimit; 421 climit_ = kIllegalLimit; 422 nesting_ = 0; 423 postpone_interrupts_nesting_ = 0; 424 interrupt_flags_ = 0; 425} 426 427 428bool StackGuard::ThreadLocal::Initialize() { 429 bool should_set_stack_limits = false; 430 if (real_climit_ == kIllegalLimit) { 431 // Takes the address of the limit variable in order to find out where 432 // the top of stack is right now. 433 const uintptr_t kLimitSize = FLAG_stack_size * KB; 434 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; 435 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); 436 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); 437 jslimit_ = SimulatorStack::JsLimitFromCLimit(limit); 438 real_climit_ = limit; 439 climit_ = limit; 440 should_set_stack_limits = true; 441 } 442 nesting_ = 0; 443 postpone_interrupts_nesting_ = 0; 444 interrupt_flags_ = 0; 445 return should_set_stack_limits; 446} 447 448 449void StackGuard::ClearThread(const ExecutionAccess& lock) { 450 thread_local_.Clear(); 451 isolate_->heap()->SetStackLimits(); 452} 453 454 455void StackGuard::InitThread(const ExecutionAccess& lock) { 456 if (thread_local_.Initialize()) isolate_->heap()->SetStackLimits(); 457 uintptr_t stored_limit = 458 Isolate::CurrentPerIsolateThreadData()->stack_limit(); 459 // You should hold the ExecutionAccess lock when you call this. 460 if (stored_limit != 0) { 461 StackGuard::SetStackLimit(stored_limit); 462 } 463} 464 465 466// --- C a l l s t o n a t i v e s --- 467 468#define RETURN_NATIVE_CALL(name, argc, argv, has_pending_exception) \ 469 do { \ 470 Object** args[argc] = argv; \ 471 ASSERT(has_pending_exception != NULL); \ 472 return Call(Isolate::Current()->name##_fun(), \ 473 Isolate::Current()->js_builtins_object(), argc, args, \ 474 has_pending_exception); \ 475 } while (false) 476 477 478Handle<Object> Execution::ToBoolean(Handle<Object> obj) { 479 // See the similar code in runtime.js:ToBoolean. 480 if (obj->IsBoolean()) return obj; 481 bool result = true; 482 if (obj->IsString()) { 483 result = Handle<String>::cast(obj)->length() != 0; 484 } else if (obj->IsNull() || obj->IsUndefined()) { 485 result = false; 486 } else if (obj->IsNumber()) { 487 double value = obj->Number(); 488 result = !((value == 0) || isnan(value)); 489 } 490 return Handle<Object>(HEAP->ToBoolean(result)); 491} 492 493 494Handle<Object> Execution::ToNumber(Handle<Object> obj, bool* exc) { 495 RETURN_NATIVE_CALL(to_number, 1, { obj.location() }, exc); 496} 497 498 499Handle<Object> Execution::ToString(Handle<Object> obj, bool* exc) { 500 RETURN_NATIVE_CALL(to_string, 1, { obj.location() }, exc); 501} 502 503 504Handle<Object> Execution::ToDetailString(Handle<Object> obj, bool* exc) { 505 RETURN_NATIVE_CALL(to_detail_string, 1, { obj.location() }, exc); 506} 507 508 509Handle<Object> Execution::ToObject(Handle<Object> obj, bool* exc) { 510 if (obj->IsJSObject()) return obj; 511 RETURN_NATIVE_CALL(to_object, 1, { obj.location() }, exc); 512} 513 514 515Handle<Object> Execution::ToInteger(Handle<Object> obj, bool* exc) { 516 RETURN_NATIVE_CALL(to_integer, 1, { obj.location() }, exc); 517} 518 519 520Handle<Object> Execution::ToUint32(Handle<Object> obj, bool* exc) { 521 RETURN_NATIVE_CALL(to_uint32, 1, { obj.location() }, exc); 522} 523 524 525Handle<Object> Execution::ToInt32(Handle<Object> obj, bool* exc) { 526 RETURN_NATIVE_CALL(to_int32, 1, { obj.location() }, exc); 527} 528 529 530Handle<Object> Execution::NewDate(double time, bool* exc) { 531 Handle<Object> time_obj = FACTORY->NewNumber(time); 532 RETURN_NATIVE_CALL(create_date, 1, { time_obj.location() }, exc); 533} 534 535 536#undef RETURN_NATIVE_CALL 537 538 539Handle<JSRegExp> Execution::NewJSRegExp(Handle<String> pattern, 540 Handle<String> flags, 541 bool* exc) { 542 Handle<JSFunction> function = Handle<JSFunction>( 543 pattern->GetIsolate()->global_context()->regexp_function()); 544 Handle<Object> re_obj = RegExpImpl::CreateRegExpLiteral( 545 function, pattern, flags, exc); 546 if (*exc) return Handle<JSRegExp>(); 547 return Handle<JSRegExp>::cast(re_obj); 548} 549 550 551Handle<Object> Execution::CharAt(Handle<String> string, uint32_t index) { 552 int int_index = static_cast<int>(index); 553 if (int_index < 0 || int_index >= string->length()) { 554 return FACTORY->undefined_value(); 555 } 556 557 Handle<Object> char_at = 558 GetProperty(Isolate::Current()->js_builtins_object(), 559 FACTORY->char_at_symbol()); 560 if (!char_at->IsJSFunction()) { 561 return FACTORY->undefined_value(); 562 } 563 564 bool caught_exception; 565 Handle<Object> index_object = FACTORY->NewNumberFromInt(int_index); 566 Object** index_arg[] = { index_object.location() }; 567 Handle<Object> result = TryCall(Handle<JSFunction>::cast(char_at), 568 string, 569 ARRAY_SIZE(index_arg), 570 index_arg, 571 &caught_exception); 572 if (caught_exception) { 573 return FACTORY->undefined_value(); 574 } 575 return result; 576} 577 578 579Handle<JSFunction> Execution::InstantiateFunction( 580 Handle<FunctionTemplateInfo> data, bool* exc) { 581 // Fast case: see if the function has already been instantiated 582 int serial_number = Smi::cast(data->serial_number())->value(); 583 Object* elm = 584 Isolate::Current()->global_context()->function_cache()-> 585 GetElementNoExceptionThrown(serial_number); 586 if (elm->IsJSFunction()) return Handle<JSFunction>(JSFunction::cast(elm)); 587 // The function has not yet been instantiated in this context; do it. 588 Object** args[1] = { Handle<Object>::cast(data).location() }; 589 Handle<Object> result = 590 Call(Isolate::Current()->instantiate_fun(), 591 Isolate::Current()->js_builtins_object(), 1, args, exc); 592 if (*exc) return Handle<JSFunction>::null(); 593 return Handle<JSFunction>::cast(result); 594} 595 596 597Handle<JSObject> Execution::InstantiateObject(Handle<ObjectTemplateInfo> data, 598 bool* exc) { 599 if (data->property_list()->IsUndefined() && 600 !data->constructor()->IsUndefined()) { 601 // Initialization to make gcc happy. 602 Object* result = NULL; 603 { 604 HandleScope scope; 605 Handle<FunctionTemplateInfo> cons_template = 606 Handle<FunctionTemplateInfo>( 607 FunctionTemplateInfo::cast(data->constructor())); 608 Handle<JSFunction> cons = InstantiateFunction(cons_template, exc); 609 if (*exc) return Handle<JSObject>::null(); 610 Handle<Object> value = New(cons, 0, NULL, exc); 611 if (*exc) return Handle<JSObject>::null(); 612 result = *value; 613 } 614 ASSERT(!*exc); 615 return Handle<JSObject>(JSObject::cast(result)); 616 } else { 617 Object** args[1] = { Handle<Object>::cast(data).location() }; 618 Handle<Object> result = 619 Call(Isolate::Current()->instantiate_fun(), 620 Isolate::Current()->js_builtins_object(), 1, args, exc); 621 if (*exc) return Handle<JSObject>::null(); 622 return Handle<JSObject>::cast(result); 623 } 624} 625 626 627void Execution::ConfigureInstance(Handle<Object> instance, 628 Handle<Object> instance_template, 629 bool* exc) { 630 Object** args[2] = { instance.location(), instance_template.location() }; 631 Execution::Call(Isolate::Current()->configure_instance_fun(), 632 Isolate::Current()->js_builtins_object(), 2, args, exc); 633} 634 635 636Handle<String> Execution::GetStackTraceLine(Handle<Object> recv, 637 Handle<JSFunction> fun, 638 Handle<Object> pos, 639 Handle<Object> is_global) { 640 const int argc = 4; 641 Object** args[argc] = { recv.location(), 642 Handle<Object>::cast(fun).location(), 643 pos.location(), 644 is_global.location() }; 645 bool caught_exception = false; 646 Handle<Object> result = 647 TryCall(Isolate::Current()->get_stack_trace_line_fun(), 648 Isolate::Current()->js_builtins_object(), argc, args, 649 &caught_exception); 650 if (caught_exception || !result->IsString()) return FACTORY->empty_symbol(); 651 return Handle<String>::cast(result); 652} 653 654 655static Object* RuntimePreempt() { 656 Isolate* isolate = Isolate::Current(); 657 658 // Clear the preempt request flag. 659 isolate->stack_guard()->Continue(PREEMPT); 660 661 ContextSwitcher::PreemptionReceived(); 662 663#ifdef ENABLE_DEBUGGER_SUPPORT 664 if (isolate->debug()->InDebugger()) { 665 // If currently in the debugger don't do any actual preemption but record 666 // that preemption occoured while in the debugger. 667 isolate->debug()->PreemptionWhileInDebugger(); 668 } else { 669 // Perform preemption. 670 v8::Unlocker unlocker; 671 Thread::YieldCPU(); 672 } 673#else 674 { // NOLINT 675 // Perform preemption. 676 v8::Unlocker unlocker; 677 Thread::YieldCPU(); 678 } 679#endif 680 681 return isolate->heap()->undefined_value(); 682} 683 684 685#ifdef ENABLE_DEBUGGER_SUPPORT 686Object* Execution::DebugBreakHelper() { 687 Isolate* isolate = Isolate::Current(); 688 689 // Just continue if breaks are disabled. 690 if (isolate->debug()->disable_break()) { 691 return isolate->heap()->undefined_value(); 692 } 693 694 // Ignore debug break during bootstrapping. 695 if (isolate->bootstrapper()->IsActive()) { 696 return isolate->heap()->undefined_value(); 697 } 698 699 { 700 JavaScriptFrameIterator it; 701 ASSERT(!it.done()); 702 Object* fun = it.frame()->function(); 703 if (fun && fun->IsJSFunction()) { 704 // Don't stop in builtin functions. 705 if (JSFunction::cast(fun)->IsBuiltin()) { 706 return isolate->heap()->undefined_value(); 707 } 708 GlobalObject* global = JSFunction::cast(fun)->context()->global(); 709 // Don't stop in debugger functions. 710 if (isolate->debug()->IsDebugGlobal(global)) { 711 return isolate->heap()->undefined_value(); 712 } 713 } 714 } 715 716 // Collect the break state before clearing the flags. 717 bool debug_command_only = 718 isolate->stack_guard()->IsDebugCommand() && 719 !isolate->stack_guard()->IsDebugBreak(); 720 721 // Clear the debug break request flag. 722 isolate->stack_guard()->Continue(DEBUGBREAK); 723 724 ProcessDebugMesssages(debug_command_only); 725 726 // Return to continue execution. 727 return isolate->heap()->undefined_value(); 728} 729 730void Execution::ProcessDebugMesssages(bool debug_command_only) { 731 // Clear the debug command request flag. 732 Isolate::Current()->stack_guard()->Continue(DEBUGCOMMAND); 733 734 HandleScope scope; 735 // Enter the debugger. Just continue if we fail to enter the debugger. 736 EnterDebugger debugger; 737 if (debugger.FailedToEnter()) { 738 return; 739 } 740 741 // Notify the debug event listeners. Indicate auto continue if the break was 742 // a debug command break. 743 Isolate::Current()->debugger()->OnDebugBreak(FACTORY->undefined_value(), 744 debug_command_only); 745} 746 747 748#endif 749 750MaybeObject* Execution::HandleStackGuardInterrupt() { 751 Isolate* isolate = Isolate::Current(); 752 StackGuard* stack_guard = isolate->stack_guard(); 753 isolate->counters()->stack_interrupts()->Increment(); 754 if (stack_guard->IsRuntimeProfilerTick()) { 755 isolate->counters()->runtime_profiler_ticks()->Increment(); 756 stack_guard->Continue(RUNTIME_PROFILER_TICK); 757 isolate->runtime_profiler()->OptimizeNow(); 758 } 759#ifdef ENABLE_DEBUGGER_SUPPORT 760 if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) { 761 DebugBreakHelper(); 762 } 763#endif 764 if (stack_guard->IsPreempted()) RuntimePreempt(); 765 if (stack_guard->IsTerminateExecution()) { 766 stack_guard->Continue(TERMINATE); 767 return isolate->TerminateExecution(); 768 } 769 if (stack_guard->IsInterrupted()) { 770 stack_guard->Continue(INTERRUPT); 771 return isolate->StackOverflow(); 772 } 773 return isolate->heap()->undefined_value(); 774} 775 776} } // namespace v8::internal 777