1 // Copyright 2011 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 "v8.h" 29 30 #include "api.h" 31 #include "bootstrapper.h" 32 #include "compiler.h" 33 #include "debug.h" 34 #include "execution.h" 35 #include "messages.h" 36 #include "platform.h" 37 #include "simulator.h" 38 #include "string-stream.h" 39 #include "vm-state-inl.h" 40 41 42 // TODO(isolates): move to isolate.cc. This stuff is kept here to 43 // simplify merging. 44 45 namespace v8 { 46 namespace internal { 47 48 ThreadLocalTop::ThreadLocalTop() { 49 InitializeInternal(); 50 // This flag may be set using v8::V8::IgnoreOutOfMemoryException() 51 // before an isolate is initialized. The initialize methods below do 52 // not touch it to preserve its value. 53 ignore_out_of_memory_ = false; 54 } 55 56 57 void ThreadLocalTop::InitializeInternal() { 58 c_entry_fp_ = 0; 59 handler_ = 0; 60 #ifdef USE_SIMULATOR 61 simulator_ = NULL; 62 #endif 63 #ifdef ENABLE_LOGGING_AND_PROFILING 64 js_entry_sp_ = NULL; 65 external_callback_ = NULL; 66 #endif 67 #ifdef ENABLE_VMSTATE_TRACKING 68 current_vm_state_ = EXTERNAL; 69 #endif 70 try_catch_handler_address_ = NULL; 71 context_ = NULL; 72 thread_id_ = ThreadId::Invalid(); 73 external_caught_exception_ = false; 74 failed_access_check_callback_ = NULL; 75 save_context_ = NULL; 76 catcher_ = NULL; 77 } 78 79 80 void ThreadLocalTop::Initialize() { 81 InitializeInternal(); 82 #ifdef USE_SIMULATOR 83 #ifdef V8_TARGET_ARCH_ARM 84 simulator_ = Simulator::current(Isolate::Current()); 85 #elif V8_TARGET_ARCH_MIPS 86 simulator_ = Simulator::current(Isolate::Current()); 87 #endif 88 #endif 89 thread_id_ = ThreadId::Current(); 90 } 91 92 93 v8::TryCatch* ThreadLocalTop::TryCatchHandler() { 94 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address()); 95 } 96 97 98 Address Isolate::get_address_from_id(Isolate::AddressId id) { 99 return isolate_addresses_[id]; 100 } 101 102 103 char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) { 104 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage); 105 Iterate(v, thread); 106 return thread_storage + sizeof(ThreadLocalTop); 107 } 108 109 110 void Isolate::IterateThread(ThreadVisitor* v) { 111 v->VisitThread(this, thread_local_top()); 112 } 113 114 115 void Isolate::IterateThread(ThreadVisitor* v, char* t) { 116 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t); 117 v->VisitThread(this, thread); 118 } 119 120 121 void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { 122 // Visit the roots from the top for a given thread. 123 Object* pending; 124 // The pending exception can sometimes be a failure. We can't show 125 // that to the GC, which only understands objects. 126 if (thread->pending_exception_->ToObject(&pending)) { 127 v->VisitPointer(&pending); 128 thread->pending_exception_ = pending; // In case GC updated it. 129 } 130 v->VisitPointer(&(thread->pending_message_obj_)); 131 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_))); 132 v->VisitPointer(BitCast<Object**>(&(thread->context_))); 133 Object* scheduled; 134 if (thread->scheduled_exception_->ToObject(&scheduled)) { 135 v->VisitPointer(&scheduled); 136 thread->scheduled_exception_ = scheduled; 137 } 138 139 for (v8::TryCatch* block = thread->TryCatchHandler(); 140 block != NULL; 141 block = TRY_CATCH_FROM_ADDRESS(block->next_)) { 142 v->VisitPointer(BitCast<Object**>(&(block->exception_))); 143 v->VisitPointer(BitCast<Object**>(&(block->message_))); 144 } 145 146 // Iterate over pointers on native execution stack. 147 for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) { 148 it.frame()->Iterate(v); 149 } 150 } 151 152 153 void Isolate::Iterate(ObjectVisitor* v) { 154 ThreadLocalTop* current_t = thread_local_top(); 155 Iterate(v, current_t); 156 } 157 158 159 void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) { 160 // The ARM simulator has a separate JS stack. We therefore register 161 // the C++ try catch handler with the simulator and get back an 162 // address that can be used for comparisons with addresses into the 163 // JS stack. When running without the simulator, the address 164 // returned will be the address of the C++ try catch handler itself. 165 Address address = reinterpret_cast<Address>( 166 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that))); 167 thread_local_top()->set_try_catch_handler_address(address); 168 } 169 170 171 void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) { 172 ASSERT(thread_local_top()->TryCatchHandler() == that); 173 thread_local_top()->set_try_catch_handler_address( 174 reinterpret_cast<Address>(that->next_)); 175 thread_local_top()->catcher_ = NULL; 176 SimulatorStack::UnregisterCTryCatch(); 177 } 178 179 180 Handle<String> Isolate::StackTraceString() { 181 if (stack_trace_nesting_level_ == 0) { 182 stack_trace_nesting_level_++; 183 HeapStringAllocator allocator; 184 StringStream::ClearMentionedObjectCache(); 185 StringStream accumulator(&allocator); 186 incomplete_message_ = &accumulator; 187 PrintStack(&accumulator); 188 Handle<String> stack_trace = accumulator.ToString(); 189 incomplete_message_ = NULL; 190 stack_trace_nesting_level_ = 0; 191 return stack_trace; 192 } else if (stack_trace_nesting_level_ == 1) { 193 stack_trace_nesting_level_++; 194 OS::PrintError( 195 "\n\nAttempt to print stack while printing stack (double fault)\n"); 196 OS::PrintError( 197 "If you are lucky you may find a partial stack dump on stdout.\n\n"); 198 incomplete_message_->OutputToStdOut(); 199 return factory()->empty_symbol(); 200 } else { 201 OS::Abort(); 202 // Unreachable 203 return factory()->empty_symbol(); 204 } 205 } 206 207 208 Handle<JSArray> Isolate::CaptureCurrentStackTrace( 209 int frame_limit, StackTrace::StackTraceOptions options) { 210 // Ensure no negative values. 211 int limit = Max(frame_limit, 0); 212 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); 213 214 Handle<String> column_key = factory()->LookupAsciiSymbol("column"); 215 Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber"); 216 Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName"); 217 Handle<String> name_or_source_url_key = 218 factory()->LookupAsciiSymbol("nameOrSourceURL"); 219 Handle<String> script_name_or_source_url_key = 220 factory()->LookupAsciiSymbol("scriptNameOrSourceURL"); 221 Handle<String> function_key = factory()->LookupAsciiSymbol("functionName"); 222 Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval"); 223 Handle<String> constructor_key = 224 factory()->LookupAsciiSymbol("isConstructor"); 225 226 StackTraceFrameIterator it(this); 227 int frames_seen = 0; 228 while (!it.done() && (frames_seen < limit)) { 229 JavaScriptFrame* frame = it.frame(); 230 // Set initial size to the maximum inlining level + 1 for the outermost 231 // function. 232 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1); 233 frame->Summarize(&frames); 234 for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) { 235 // Create a JSObject to hold the information for the StackFrame. 236 Handle<JSObject> stackFrame = factory()->NewJSObject(object_function()); 237 238 Handle<JSFunction> fun = frames[i].function(); 239 Handle<Script> script(Script::cast(fun->shared()->script())); 240 241 if (options & StackTrace::kLineNumber) { 242 int script_line_offset = script->line_offset()->value(); 243 int position = frames[i].code()->SourcePosition(frames[i].pc()); 244 int line_number = GetScriptLineNumber(script, position); 245 // line_number is already shifted by the script_line_offset. 246 int relative_line_number = line_number - script_line_offset; 247 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) { 248 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends())); 249 int start = (relative_line_number == 0) ? 0 : 250 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1; 251 int column_offset = position - start; 252 if (relative_line_number == 0) { 253 // For the case where the code is on the same line as the script 254 // tag. 255 column_offset += script->column_offset()->value(); 256 } 257 SetLocalPropertyNoThrow(stackFrame, column_key, 258 Handle<Smi>(Smi::FromInt(column_offset + 1))); 259 } 260 SetLocalPropertyNoThrow(stackFrame, line_key, 261 Handle<Smi>(Smi::FromInt(line_number + 1))); 262 } 263 264 if (options & StackTrace::kScriptName) { 265 Handle<Object> script_name(script->name(), this); 266 SetLocalPropertyNoThrow(stackFrame, script_key, script_name); 267 } 268 269 if (options & StackTrace::kScriptNameOrSourceURL) { 270 Handle<Object> script_name(script->name(), this); 271 Handle<JSValue> script_wrapper = GetScriptWrapper(script); 272 Handle<Object> property = GetProperty(script_wrapper, 273 name_or_source_url_key); 274 ASSERT(property->IsJSFunction()); 275 Handle<JSFunction> method = Handle<JSFunction>::cast(property); 276 bool caught_exception; 277 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, 278 NULL, &caught_exception); 279 if (caught_exception) { 280 result = factory()->undefined_value(); 281 } 282 SetLocalPropertyNoThrow(stackFrame, script_name_or_source_url_key, 283 result); 284 } 285 286 if (options & StackTrace::kFunctionName) { 287 Handle<Object> fun_name(fun->shared()->name(), this); 288 if (fun_name->ToBoolean()->IsFalse()) { 289 fun_name = Handle<Object>(fun->shared()->inferred_name(), this); 290 } 291 SetLocalPropertyNoThrow(stackFrame, function_key, fun_name); 292 } 293 294 if (options & StackTrace::kIsEval) { 295 int type = Smi::cast(script->compilation_type())->value(); 296 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ? 297 factory()->true_value() : factory()->false_value(); 298 SetLocalPropertyNoThrow(stackFrame, eval_key, is_eval); 299 } 300 301 if (options & StackTrace::kIsConstructor) { 302 Handle<Object> is_constructor = (frames[i].is_constructor()) ? 303 factory()->true_value() : factory()->false_value(); 304 SetLocalPropertyNoThrow(stackFrame, constructor_key, is_constructor); 305 } 306 307 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame); 308 frames_seen++; 309 } 310 it.Advance(); 311 } 312 313 stack_trace->set_length(Smi::FromInt(frames_seen)); 314 return stack_trace; 315 } 316 317 318 void Isolate::PrintStack() { 319 if (stack_trace_nesting_level_ == 0) { 320 stack_trace_nesting_level_++; 321 322 StringAllocator* allocator; 323 if (preallocated_message_space_ == NULL) { 324 allocator = new HeapStringAllocator(); 325 } else { 326 allocator = preallocated_message_space_; 327 } 328 329 StringStream::ClearMentionedObjectCache(); 330 StringStream accumulator(allocator); 331 incomplete_message_ = &accumulator; 332 PrintStack(&accumulator); 333 accumulator.OutputToStdOut(); 334 InitializeLoggingAndCounters(); 335 accumulator.Log(); 336 incomplete_message_ = NULL; 337 stack_trace_nesting_level_ = 0; 338 if (preallocated_message_space_ == NULL) { 339 // Remove the HeapStringAllocator created above. 340 delete allocator; 341 } 342 } else if (stack_trace_nesting_level_ == 1) { 343 stack_trace_nesting_level_++; 344 OS::PrintError( 345 "\n\nAttempt to print stack while printing stack (double fault)\n"); 346 OS::PrintError( 347 "If you are lucky you may find a partial stack dump on stdout.\n\n"); 348 incomplete_message_->OutputToStdOut(); 349 } 350 } 351 352 353 static void PrintFrames(StringStream* accumulator, 354 StackFrame::PrintMode mode) { 355 StackFrameIterator it; 356 for (int i = 0; !it.done(); it.Advance()) { 357 it.frame()->Print(accumulator, mode, i++); 358 } 359 } 360 361 362 void Isolate::PrintStack(StringStream* accumulator) { 363 if (!IsInitialized()) { 364 accumulator->Add( 365 "\n==== Stack trace is not available ==========================\n\n"); 366 accumulator->Add( 367 "\n==== Isolate for the thread is not initialized =============\n\n"); 368 return; 369 } 370 // The MentionedObjectCache is not GC-proof at the moment. 371 AssertNoAllocation nogc; 372 ASSERT(StringStream::IsMentionedObjectCacheClear()); 373 374 // Avoid printing anything if there are no frames. 375 if (c_entry_fp(thread_local_top()) == 0) return; 376 377 accumulator->Add( 378 "\n==== Stack trace ============================================\n\n"); 379 PrintFrames(accumulator, StackFrame::OVERVIEW); 380 381 accumulator->Add( 382 "\n==== Details ================================================\n\n"); 383 PrintFrames(accumulator, StackFrame::DETAILS); 384 385 accumulator->PrintMentionedObjectCache(); 386 accumulator->Add("=====================\n\n"); 387 } 388 389 390 void Isolate::SetFailedAccessCheckCallback( 391 v8::FailedAccessCheckCallback callback) { 392 thread_local_top()->failed_access_check_callback_ = callback; 393 } 394 395 396 void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { 397 if (!thread_local_top()->failed_access_check_callback_) return; 398 399 ASSERT(receiver->IsAccessCheckNeeded()); 400 ASSERT(context()); 401 402 // Get the data object from access check info. 403 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor()); 404 if (!constructor->shared()->IsApiFunction()) return; 405 Object* data_obj = 406 constructor->shared()->get_api_func_data()->access_check_info(); 407 if (data_obj == heap_.undefined_value()) return; 408 409 HandleScope scope; 410 Handle<JSObject> receiver_handle(receiver); 411 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data()); 412 thread_local_top()->failed_access_check_callback_( 413 v8::Utils::ToLocal(receiver_handle), 414 type, 415 v8::Utils::ToLocal(data)); 416 } 417 418 419 enum MayAccessDecision { 420 YES, NO, UNKNOWN 421 }; 422 423 424 static MayAccessDecision MayAccessPreCheck(Isolate* isolate, 425 JSObject* receiver, 426 v8::AccessType type) { 427 // During bootstrapping, callback functions are not enabled yet. 428 if (isolate->bootstrapper()->IsActive()) return YES; 429 430 if (receiver->IsJSGlobalProxy()) { 431 Object* receiver_context = JSGlobalProxy::cast(receiver)->context(); 432 if (!receiver_context->IsContext()) return NO; 433 434 // Get the global context of current top context. 435 // avoid using Isolate::global_context() because it uses Handle. 436 Context* global_context = isolate->context()->global()->global_context(); 437 if (receiver_context == global_context) return YES; 438 439 if (Context::cast(receiver_context)->security_token() == 440 global_context->security_token()) 441 return YES; 442 } 443 444 return UNKNOWN; 445 } 446 447 448 bool Isolate::MayNamedAccess(JSObject* receiver, Object* key, 449 v8::AccessType type) { 450 ASSERT(receiver->IsAccessCheckNeeded()); 451 452 // The callers of this method are not expecting a GC. 453 AssertNoAllocation no_gc; 454 455 // Skip checks for hidden properties access. Note, we do not 456 // require existence of a context in this case. 457 if (key == heap_.hidden_symbol()) return true; 458 459 // Check for compatibility between the security tokens in the 460 // current lexical context and the accessed object. 461 ASSERT(context()); 462 463 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type); 464 if (decision != UNKNOWN) return decision == YES; 465 466 // Get named access check callback 467 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor()); 468 if (!constructor->shared()->IsApiFunction()) return false; 469 470 Object* data_obj = 471 constructor->shared()->get_api_func_data()->access_check_info(); 472 if (data_obj == heap_.undefined_value()) return false; 473 474 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback(); 475 v8::NamedSecurityCallback callback = 476 v8::ToCData<v8::NamedSecurityCallback>(fun_obj); 477 478 if (!callback) return false; 479 480 HandleScope scope(this); 481 Handle<JSObject> receiver_handle(receiver, this); 482 Handle<Object> key_handle(key, this); 483 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this); 484 LOG(this, ApiNamedSecurityCheck(key)); 485 bool result = false; 486 { 487 // Leaving JavaScript. 488 VMState state(this, EXTERNAL); 489 result = callback(v8::Utils::ToLocal(receiver_handle), 490 v8::Utils::ToLocal(key_handle), 491 type, 492 v8::Utils::ToLocal(data)); 493 } 494 return result; 495 } 496 497 498 bool Isolate::MayIndexedAccess(JSObject* receiver, 499 uint32_t index, 500 v8::AccessType type) { 501 ASSERT(receiver->IsAccessCheckNeeded()); 502 // Check for compatibility between the security tokens in the 503 // current lexical context and the accessed object. 504 ASSERT(context()); 505 506 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type); 507 if (decision != UNKNOWN) return decision == YES; 508 509 // Get indexed access check callback 510 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor()); 511 if (!constructor->shared()->IsApiFunction()) return false; 512 513 Object* data_obj = 514 constructor->shared()->get_api_func_data()->access_check_info(); 515 if (data_obj == heap_.undefined_value()) return false; 516 517 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback(); 518 v8::IndexedSecurityCallback callback = 519 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj); 520 521 if (!callback) return false; 522 523 HandleScope scope(this); 524 Handle<JSObject> receiver_handle(receiver, this); 525 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this); 526 LOG(this, ApiIndexedSecurityCheck(index)); 527 bool result = false; 528 { 529 // Leaving JavaScript. 530 VMState state(this, EXTERNAL); 531 result = callback(v8::Utils::ToLocal(receiver_handle), 532 index, 533 type, 534 v8::Utils::ToLocal(data)); 535 } 536 return result; 537 } 538 539 540 const char* const Isolate::kStackOverflowMessage = 541 "Uncaught RangeError: Maximum call stack size exceeded"; 542 543 544 Failure* Isolate::StackOverflow() { 545 HandleScope scope; 546 Handle<String> key = factory()->stack_overflow_symbol(); 547 Handle<JSObject> boilerplate = 548 Handle<JSObject>::cast(GetProperty(js_builtins_object(), key)); 549 Handle<Object> exception = Copy(boilerplate); 550 // TODO(1240995): To avoid having to call JavaScript code to compute 551 // the message for stack overflow exceptions which is very likely to 552 // double fault with another stack overflow exception, we use a 553 // precomputed message. 554 DoThrow(*exception, NULL); 555 return Failure::Exception(); 556 } 557 558 559 Failure* Isolate::TerminateExecution() { 560 DoThrow(heap_.termination_exception(), NULL); 561 return Failure::Exception(); 562 } 563 564 565 Failure* Isolate::Throw(Object* exception, MessageLocation* location) { 566 DoThrow(exception, location); 567 return Failure::Exception(); 568 } 569 570 571 Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) { 572 bool can_be_caught_externally = false; 573 ShouldReportException(&can_be_caught_externally, 574 is_catchable_by_javascript(exception)); 575 thread_local_top()->catcher_ = can_be_caught_externally ? 576 try_catch_handler() : NULL; 577 578 // Set the exception being re-thrown. 579 set_pending_exception(exception); 580 if (exception->IsFailure()) return exception->ToFailureUnchecked(); 581 return Failure::Exception(); 582 } 583 584 585 Failure* Isolate::ThrowIllegalOperation() { 586 return Throw(heap_.illegal_access_symbol()); 587 } 588 589 590 void Isolate::ScheduleThrow(Object* exception) { 591 // When scheduling a throw we first throw the exception to get the 592 // error reporting if it is uncaught before rescheduling it. 593 Throw(exception); 594 thread_local_top()->scheduled_exception_ = pending_exception(); 595 thread_local_top()->external_caught_exception_ = false; 596 clear_pending_exception(); 597 } 598 599 600 Failure* Isolate::PromoteScheduledException() { 601 MaybeObject* thrown = scheduled_exception(); 602 clear_scheduled_exception(); 603 // Re-throw the exception to avoid getting repeated error reporting. 604 return ReThrow(thrown); 605 } 606 607 608 void Isolate::PrintCurrentStackTrace(FILE* out) { 609 StackTraceFrameIterator it(this); 610 while (!it.done()) { 611 HandleScope scope; 612 // Find code position if recorded in relocation info. 613 JavaScriptFrame* frame = it.frame(); 614 int pos = frame->LookupCode()->SourcePosition(frame->pc()); 615 Handle<Object> pos_obj(Smi::FromInt(pos)); 616 // Fetch function and receiver. 617 Handle<JSFunction> fun(JSFunction::cast(frame->function())); 618 Handle<Object> recv(frame->receiver()); 619 // Advance to the next JavaScript frame and determine if the 620 // current frame is the top-level frame. 621 it.Advance(); 622 Handle<Object> is_top_level = it.done() 623 ? factory()->true_value() 624 : factory()->false_value(); 625 // Generate and print stack trace line. 626 Handle<String> line = 627 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level); 628 if (line->length() > 0) { 629 line->PrintOn(out); 630 fprintf(out, "\n"); 631 } 632 } 633 } 634 635 636 void Isolate::ComputeLocation(MessageLocation* target) { 637 *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1); 638 StackTraceFrameIterator it(this); 639 if (!it.done()) { 640 JavaScriptFrame* frame = it.frame(); 641 JSFunction* fun = JSFunction::cast(frame->function()); 642 Object* script = fun->shared()->script(); 643 if (script->IsScript() && 644 !(Script::cast(script)->source()->IsUndefined())) { 645 int pos = frame->LookupCode()->SourcePosition(frame->pc()); 646 // Compute the location from the function and the reloc info. 647 Handle<Script> casted_script(Script::cast(script)); 648 *target = MessageLocation(casted_script, pos, pos + 1); 649 } 650 } 651 } 652 653 654 bool Isolate::ShouldReportException(bool* can_be_caught_externally, 655 bool catchable_by_javascript) { 656 // Find the top-most try-catch handler. 657 StackHandler* handler = 658 StackHandler::FromAddress(Isolate::handler(thread_local_top())); 659 while (handler != NULL && !handler->is_try_catch()) { 660 handler = handler->next(); 661 } 662 663 // Get the address of the external handler so we can compare the address to 664 // determine which one is closer to the top of the stack. 665 Address external_handler_address = 666 thread_local_top()->try_catch_handler_address(); 667 668 // The exception has been externally caught if and only if there is 669 // an external handler which is on top of the top-most try-catch 670 // handler. 671 *can_be_caught_externally = external_handler_address != NULL && 672 (handler == NULL || handler->address() > external_handler_address || 673 !catchable_by_javascript); 674 675 if (*can_be_caught_externally) { 676 // Only report the exception if the external handler is verbose. 677 return try_catch_handler()->is_verbose_; 678 } else { 679 // Report the exception if it isn't caught by JavaScript code. 680 return handler == NULL; 681 } 682 } 683 684 685 void Isolate::DoThrow(MaybeObject* exception, MessageLocation* location) { 686 ASSERT(!has_pending_exception()); 687 688 HandleScope scope; 689 Object* exception_object = Smi::FromInt(0); 690 bool is_object = exception->ToObject(&exception_object); 691 Handle<Object> exception_handle(exception_object); 692 693 // Determine reporting and whether the exception is caught externally. 694 bool catchable_by_javascript = is_catchable_by_javascript(exception); 695 // Only real objects can be caught by JS. 696 ASSERT(!catchable_by_javascript || is_object); 697 bool can_be_caught_externally = false; 698 bool should_report_exception = 699 ShouldReportException(&can_be_caught_externally, catchable_by_javascript); 700 bool report_exception = catchable_by_javascript && should_report_exception; 701 702 #ifdef ENABLE_DEBUGGER_SUPPORT 703 // Notify debugger of exception. 704 if (catchable_by_javascript) { 705 debugger_->OnException(exception_handle, report_exception); 706 } 707 #endif 708 709 // Generate the message. 710 Handle<Object> message_obj; 711 MessageLocation potential_computed_location; 712 bool try_catch_needs_message = 713 can_be_caught_externally && 714 try_catch_handler()->capture_message_; 715 if (report_exception || try_catch_needs_message) { 716 if (location == NULL) { 717 // If no location was specified we use a computed one instead 718 ComputeLocation(&potential_computed_location); 719 location = &potential_computed_location; 720 } 721 if (!bootstrapper()->IsActive()) { 722 // It's not safe to try to make message objects or collect stack 723 // traces while the bootstrapper is active since the infrastructure 724 // may not have been properly initialized. 725 Handle<String> stack_trace; 726 if (FLAG_trace_exception) stack_trace = StackTraceString(); 727 Handle<JSArray> stack_trace_object; 728 if (report_exception && capture_stack_trace_for_uncaught_exceptions_) { 729 stack_trace_object = CaptureCurrentStackTrace( 730 stack_trace_for_uncaught_exceptions_frame_limit_, 731 stack_trace_for_uncaught_exceptions_options_); 732 } 733 ASSERT(is_object); // Can't use the handle unless there's a real object. 734 message_obj = MessageHandler::MakeMessageObject("uncaught_exception", 735 location, HandleVector<Object>(&exception_handle, 1), stack_trace, 736 stack_trace_object); 737 } 738 } 739 740 // Save the message for reporting if the the exception remains uncaught. 741 thread_local_top()->has_pending_message_ = report_exception; 742 if (!message_obj.is_null()) { 743 thread_local_top()->pending_message_obj_ = *message_obj; 744 if (location != NULL) { 745 thread_local_top()->pending_message_script_ = *location->script(); 746 thread_local_top()->pending_message_start_pos_ = location->start_pos(); 747 thread_local_top()->pending_message_end_pos_ = location->end_pos(); 748 } 749 } 750 751 // Do not forget to clean catcher_ if currently thrown exception cannot 752 // be caught. If necessary, ReThrow will update the catcher. 753 thread_local_top()->catcher_ = can_be_caught_externally ? 754 try_catch_handler() : NULL; 755 756 // NOTE: Notifying the debugger or generating the message 757 // may have caused new exceptions. For now, we just ignore 758 // that and set the pending exception to the original one. 759 if (is_object) { 760 set_pending_exception(*exception_handle); 761 } else { 762 // Failures are not on the heap so they neither need nor work with handles. 763 ASSERT(exception_handle->IsFailure()); 764 set_pending_exception(exception); 765 } 766 } 767 768 769 bool Isolate::IsExternallyCaught() { 770 ASSERT(has_pending_exception()); 771 772 if ((thread_local_top()->catcher_ == NULL) || 773 (try_catch_handler() != thread_local_top()->catcher_)) { 774 // When throwing the exception, we found no v8::TryCatch 775 // which should care about this exception. 776 return false; 777 } 778 779 if (!is_catchable_by_javascript(pending_exception())) { 780 return true; 781 } 782 783 // Get the address of the external handler so we can compare the address to 784 // determine which one is closer to the top of the stack. 785 Address external_handler_address = 786 thread_local_top()->try_catch_handler_address(); 787 ASSERT(external_handler_address != NULL); 788 789 // The exception has been externally caught if and only if there is 790 // an external handler which is on top of the top-most try-finally 791 // handler. 792 // There should be no try-catch blocks as they would prohibit us from 793 // finding external catcher in the first place (see catcher_ check above). 794 // 795 // Note, that finally clause would rethrow an exception unless it's 796 // aborted by jumps in control flow like return, break, etc. and we'll 797 // have another chances to set proper v8::TryCatch. 798 StackHandler* handler = 799 StackHandler::FromAddress(Isolate::handler(thread_local_top())); 800 while (handler != NULL && handler->address() < external_handler_address) { 801 ASSERT(!handler->is_try_catch()); 802 if (handler->is_try_finally()) return false; 803 804 handler = handler->next(); 805 } 806 807 return true; 808 } 809 810 811 void Isolate::ReportPendingMessages() { 812 ASSERT(has_pending_exception()); 813 PropagatePendingExceptionToExternalTryCatch(); 814 815 // If the pending exception is OutOfMemoryException set out_of_memory in 816 // the global context. Note: We have to mark the global context here 817 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to 818 // set it. 819 HandleScope scope; 820 if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) { 821 context()->mark_out_of_memory(); 822 } else if (thread_local_top_.pending_exception_ == 823 heap()->termination_exception()) { 824 // Do nothing: if needed, the exception has been already propagated to 825 // v8::TryCatch. 826 } else { 827 if (thread_local_top_.has_pending_message_) { 828 thread_local_top_.has_pending_message_ = false; 829 if (!thread_local_top_.pending_message_obj_->IsTheHole()) { 830 HandleScope scope; 831 Handle<Object> message_obj(thread_local_top_.pending_message_obj_); 832 if (thread_local_top_.pending_message_script_ != NULL) { 833 Handle<Script> script(thread_local_top_.pending_message_script_); 834 int start_pos = thread_local_top_.pending_message_start_pos_; 835 int end_pos = thread_local_top_.pending_message_end_pos_; 836 MessageLocation location(script, start_pos, end_pos); 837 MessageHandler::ReportMessage(this, &location, message_obj); 838 } else { 839 MessageHandler::ReportMessage(this, NULL, message_obj); 840 } 841 } 842 } 843 } 844 clear_pending_message(); 845 } 846 847 848 void Isolate::TraceException(bool flag) { 849 FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use. 850 } 851 852 853 bool Isolate::OptionalRescheduleException(bool is_bottom_call) { 854 ASSERT(has_pending_exception()); 855 PropagatePendingExceptionToExternalTryCatch(); 856 857 // Allways reschedule out of memory exceptions. 858 if (!is_out_of_memory()) { 859 bool is_termination_exception = 860 pending_exception() == heap_.termination_exception(); 861 862 // Do not reschedule the exception if this is the bottom call. 863 bool clear_exception = is_bottom_call; 864 865 if (is_termination_exception) { 866 if (is_bottom_call) { 867 thread_local_top()->external_caught_exception_ = false; 868 clear_pending_exception(); 869 return false; 870 } 871 } else if (thread_local_top()->external_caught_exception_) { 872 // If the exception is externally caught, clear it if there are no 873 // JavaScript frames on the way to the C++ frame that has the 874 // external handler. 875 ASSERT(thread_local_top()->try_catch_handler_address() != NULL); 876 Address external_handler_address = 877 thread_local_top()->try_catch_handler_address(); 878 JavaScriptFrameIterator it; 879 if (it.done() || (it.frame()->sp() > external_handler_address)) { 880 clear_exception = true; 881 } 882 } 883 884 // Clear the exception if needed. 885 if (clear_exception) { 886 thread_local_top()->external_caught_exception_ = false; 887 clear_pending_exception(); 888 return false; 889 } 890 } 891 892 // Reschedule the exception. 893 thread_local_top()->scheduled_exception_ = pending_exception(); 894 clear_pending_exception(); 895 return true; 896 } 897 898 899 void Isolate::SetCaptureStackTraceForUncaughtExceptions( 900 bool capture, 901 int frame_limit, 902 StackTrace::StackTraceOptions options) { 903 capture_stack_trace_for_uncaught_exceptions_ = capture; 904 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit; 905 stack_trace_for_uncaught_exceptions_options_ = options; 906 } 907 908 909 bool Isolate::is_out_of_memory() { 910 if (has_pending_exception()) { 911 MaybeObject* e = pending_exception(); 912 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) { 913 return true; 914 } 915 } 916 if (has_scheduled_exception()) { 917 MaybeObject* e = scheduled_exception(); 918 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) { 919 return true; 920 } 921 } 922 return false; 923 } 924 925 926 Handle<Context> Isolate::global_context() { 927 GlobalObject* global = thread_local_top()->context_->global(); 928 return Handle<Context>(global->global_context()); 929 } 930 931 932 Handle<Context> Isolate::GetCallingGlobalContext() { 933 JavaScriptFrameIterator it; 934 #ifdef ENABLE_DEBUGGER_SUPPORT 935 if (debug_->InDebugger()) { 936 while (!it.done()) { 937 JavaScriptFrame* frame = it.frame(); 938 Context* context = Context::cast(frame->context()); 939 if (context->global_context() == *debug_->debug_context()) { 940 it.Advance(); 941 } else { 942 break; 943 } 944 } 945 } 946 #endif // ENABLE_DEBUGGER_SUPPORT 947 if (it.done()) return Handle<Context>::null(); 948 JavaScriptFrame* frame = it.frame(); 949 Context* context = Context::cast(frame->context()); 950 return Handle<Context>(context->global_context()); 951 } 952 953 954 char* Isolate::ArchiveThread(char* to) { 955 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) { 956 RuntimeProfiler::IsolateExitedJS(this); 957 } 958 memcpy(to, reinterpret_cast<char*>(thread_local_top()), 959 sizeof(ThreadLocalTop)); 960 InitializeThreadLocal(); 961 return to + sizeof(ThreadLocalTop); 962 } 963 964 965 char* Isolate::RestoreThread(char* from) { 966 memcpy(reinterpret_cast<char*>(thread_local_top()), from, 967 sizeof(ThreadLocalTop)); 968 // This might be just paranoia, but it seems to be needed in case a 969 // thread_local_top_ is restored on a separate OS thread. 970 #ifdef USE_SIMULATOR 971 #ifdef V8_TARGET_ARCH_ARM 972 thread_local_top()->simulator_ = Simulator::current(this); 973 #elif V8_TARGET_ARCH_MIPS 974 thread_local_top()->simulator_ = Simulator::current(this); 975 #endif 976 #endif 977 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) { 978 RuntimeProfiler::IsolateEnteredJS(this); 979 } 980 return from + sizeof(ThreadLocalTop); 981 } 982 983 } } // namespace v8::internal 984