// Copyright 2006-2008 the V8 project authors. All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following // disclaimer in the documentation and/or other materials provided // with the distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "v8.h" #include "api.h" #include "bootstrapper.h" #include "compiler.h" #include "debug.h" #include "execution.h" #include "messages.h" #include "platform.h" #include "simulator.h" #include "string-stream.h" #include "vm-state-inl.h" // TODO(isolates): move to isolate.cc. This stuff is kept here to // simplify merging. namespace v8 { namespace internal { v8::TryCatch* ThreadLocalTop::TryCatchHandler() { return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address()); } void ThreadLocalTop::Initialize() { c_entry_fp_ = 0; handler_ = 0; #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM simulator_ = Simulator::current(Isolate::Current()); #elif V8_TARGET_ARCH_MIPS simulator_ = Simulator::current(Isolate::Current()); #endif #endif #ifdef ENABLE_LOGGING_AND_PROFILING js_entry_sp_ = NULL; external_callback_ = NULL; #endif #ifdef ENABLE_VMSTATE_TRACKING current_vm_state_ = EXTERNAL; #endif try_catch_handler_address_ = NULL; context_ = NULL; int id = Isolate::Current()->thread_manager()->CurrentId(); thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id; external_caught_exception_ = false; failed_access_check_callback_ = NULL; save_context_ = NULL; catcher_ = NULL; } Address Isolate::get_address_from_id(Isolate::AddressId id) { return isolate_addresses_[id]; } char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) { ThreadLocalTop* thread = reinterpret_cast(thread_storage); Iterate(v, thread); return thread_storage + sizeof(ThreadLocalTop); } void Isolate::IterateThread(ThreadVisitor* v) { v->VisitThread(this, thread_local_top()); } void Isolate::IterateThread(ThreadVisitor* v, char* t) { ThreadLocalTop* thread = reinterpret_cast(t); v->VisitThread(this, thread); } void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { // Visit the roots from the top for a given thread. Object* pending; // The pending exception can sometimes be a failure. We can't show // that to the GC, which only understands objects. if (thread->pending_exception_->ToObject(&pending)) { v->VisitPointer(&pending); thread->pending_exception_ = pending; // In case GC updated it. } v->VisitPointer(&(thread->pending_message_obj_)); v->VisitPointer(BitCast(&(thread->pending_message_script_))); v->VisitPointer(BitCast(&(thread->context_))); Object* scheduled; if (thread->scheduled_exception_->ToObject(&scheduled)) { v->VisitPointer(&scheduled); thread->scheduled_exception_ = scheduled; } for (v8::TryCatch* block = thread->TryCatchHandler(); block != NULL; block = TRY_CATCH_FROM_ADDRESS(block->next_)) { v->VisitPointer(BitCast(&(block->exception_))); v->VisitPointer(BitCast(&(block->message_))); } // Iterate over pointers on native execution stack. for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) { it.frame()->Iterate(v); } } void Isolate::Iterate(ObjectVisitor* v) { ThreadLocalTop* current_t = thread_local_top(); Iterate(v, current_t); } void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) { // The ARM simulator has a separate JS stack. We therefore register // the C++ try catch handler with the simulator and get back an // address that can be used for comparisons with addresses into the // JS stack. When running without the simulator, the address // returned will be the address of the C++ try catch handler itself. Address address = reinterpret_cast
( SimulatorStack::RegisterCTryCatch(reinterpret_cast(that))); thread_local_top()->set_try_catch_handler_address(address); } void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) { ASSERT(thread_local_top()->TryCatchHandler() == that); thread_local_top()->set_try_catch_handler_address( reinterpret_cast
(that->next_)); thread_local_top()->catcher_ = NULL; SimulatorStack::UnregisterCTryCatch(); } Handle Isolate::StackTraceString() { if (stack_trace_nesting_level_ == 0) { stack_trace_nesting_level_++; HeapStringAllocator allocator; StringStream::ClearMentionedObjectCache(); StringStream accumulator(&allocator); incomplete_message_ = &accumulator; PrintStack(&accumulator); Handle stack_trace = accumulator.ToString(); incomplete_message_ = NULL; stack_trace_nesting_level_ = 0; return stack_trace; } else if (stack_trace_nesting_level_ == 1) { stack_trace_nesting_level_++; OS::PrintError( "\n\nAttempt to print stack while printing stack (double fault)\n"); OS::PrintError( "If you are lucky you may find a partial stack dump on stdout.\n\n"); incomplete_message_->OutputToStdOut(); return factory()->empty_symbol(); } else { OS::Abort(); // Unreachable return factory()->empty_symbol(); } } Handle Isolate::CaptureCurrentStackTrace( int frame_limit, StackTrace::StackTraceOptions options) { // Ensure no negative values. int limit = Max(frame_limit, 0); Handle stack_trace = factory()->NewJSArray(frame_limit); Handle column_key = factory()->LookupAsciiSymbol("column"); Handle line_key = factory()->LookupAsciiSymbol("lineNumber"); Handle script_key = factory()->LookupAsciiSymbol("scriptName"); Handle name_or_source_url_key = factory()->LookupAsciiSymbol("nameOrSourceURL"); Handle script_name_or_source_url_key = factory()->LookupAsciiSymbol("scriptNameOrSourceURL"); Handle function_key = factory()->LookupAsciiSymbol("functionName"); Handle eval_key = factory()->LookupAsciiSymbol("isEval"); Handle constructor_key = factory()->LookupAsciiSymbol("isConstructor"); StackTraceFrameIterator it(this); int frames_seen = 0; while (!it.done() && (frames_seen < limit)) { JavaScriptFrame* frame = it.frame(); // Set initial size to the maximum inlining level + 1 for the outermost // function. List frames(Compiler::kMaxInliningLevels + 1); frame->Summarize(&frames); for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) { // Create a JSObject to hold the information for the StackFrame. Handle stackFrame = factory()->NewJSObject(object_function()); Handle fun = frames[i].function(); Handle