diff options
Diffstat (limited to 'src/top.cc')
-rw-r--r-- | src/top.cc | 608 |
1 files changed, 218 insertions, 390 deletions
@@ -37,31 +37,12 @@ #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 { -#ifdef ENABLE_LOGGING_AND_PROFILING -Semaphore* Top::runtime_profiler_semaphore_ = NULL; -#endif -ThreadLocalTop Top::thread_local_; -Mutex* Top::break_access_ = OS::CreateMutex(); - -NoAllocationStringAllocator* preallocated_message_space = NULL; - -bool capture_stack_trace_for_uncaught_exceptions = false; -int stack_trace_for_uncaught_exceptions_frame_limit = 0; -StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options = - StackTrace::kOverview; - -Address top_addresses[] = { -#define C(name) reinterpret_cast<Address>(Top::name()), - TOP_ADDRESS_LIST(C) - TOP_ADDRESS_LIST_PROF(C) -#undef C - NULL -}; - - v8::TryCatch* ThreadLocalTop::TryCatchHandler() { return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address()); } @@ -72,9 +53,9 @@ void ThreadLocalTop::Initialize() { handler_ = 0; #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - simulator_ = Simulator::current(); + simulator_ = Simulator::current(Isolate::Current()); #elif V8_TARGET_ARCH_MIPS - simulator_ = assembler::mips::Simulator::current(); + simulator_ = Simulator::current(Isolate::Current()); #endif #endif #ifdef ENABLE_LOGGING_AND_PROFILING @@ -83,11 +64,10 @@ void ThreadLocalTop::Initialize() { #endif #ifdef ENABLE_VMSTATE_TRACKING current_vm_state_ = EXTERNAL; - runtime_profiler_state_ = Top::PROF_NOT_IN_JS; #endif try_catch_handler_address_ = NULL; context_ = NULL; - int id = ThreadManager::CurrentId(); + int id = Isolate::Current()->thread_manager()->CurrentId(); thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id; external_caught_exception_ = false; failed_access_check_callback_ = NULL; @@ -96,32 +76,32 @@ void ThreadLocalTop::Initialize() { } -Address Top::get_address_from_id(Top::AddressId id) { - return top_addresses[id]; +Address Isolate::get_address_from_id(Isolate::AddressId id) { + return isolate_addresses_[id]; } -char* Top::Iterate(ObjectVisitor* v, char* thread_storage) { +char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) { ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage); Iterate(v, thread); return thread_storage + sizeof(ThreadLocalTop); } -void Top::IterateThread(ThreadVisitor* v) { - v->VisitThread(&thread_local_); +void Isolate::IterateThread(ThreadVisitor* v) { + v->VisitThread(thread_local_top()); } -void Top::IterateThread(ThreadVisitor* v, char* t) { +void Isolate::IterateThread(ThreadVisitor* v, char* t) { ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t); v->VisitThread(thread); } -void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { +void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { // Visit the roots from the top for a given thread. - Object *pending; + 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)) { @@ -151,176 +131,13 @@ void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) { } -void Top::Iterate(ObjectVisitor* v) { - ThreadLocalTop* current_t = &thread_local_; +void Isolate::Iterate(ObjectVisitor* v) { + ThreadLocalTop* current_t = thread_local_top(); Iterate(v, current_t); } -void Top::InitializeThreadLocal() { - thread_local_.Initialize(); - clear_pending_exception(); - clear_pending_message(); - clear_scheduled_exception(); -} - - -// Create a dummy thread that will wait forever on a semaphore. The only -// purpose for this thread is to have some stack area to save essential data -// into for use by a stacks only core dump (aka minidump). -class PreallocatedMemoryThread: public Thread { - public: - PreallocatedMemoryThread() - : Thread("v8:PreallocMem"), - keep_running_(true) { - wait_for_ever_semaphore_ = OS::CreateSemaphore(0); - data_ready_semaphore_ = OS::CreateSemaphore(0); - } - - // When the thread starts running it will allocate a fixed number of bytes - // on the stack and publish the location of this memory for others to use. - void Run() { - EmbeddedVector<char, 15 * 1024> local_buffer; - - // Initialize the buffer with a known good value. - OS::StrNCpy(local_buffer, "Trace data was not generated.\n", - local_buffer.length()); - - // Publish the local buffer and signal its availability. - data_ = local_buffer.start(); - length_ = local_buffer.length(); - data_ready_semaphore_->Signal(); - - while (keep_running_) { - // This thread will wait here until the end of time. - wait_for_ever_semaphore_->Wait(); - } - - // Make sure we access the buffer after the wait to remove all possibility - // of it being optimized away. - OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n", - local_buffer.length()); - } - - static char* data() { - if (data_ready_semaphore_ != NULL) { - // Initial access is guarded until the data has been published. - data_ready_semaphore_->Wait(); - delete data_ready_semaphore_; - data_ready_semaphore_ = NULL; - } - return data_; - } - - static unsigned length() { - if (data_ready_semaphore_ != NULL) { - // Initial access is guarded until the data has been published. - data_ready_semaphore_->Wait(); - delete data_ready_semaphore_; - data_ready_semaphore_ = NULL; - } - return length_; - } - - static void StartThread() { - if (the_thread_ != NULL) return; - - the_thread_ = new PreallocatedMemoryThread(); - the_thread_->Start(); - } - - // Stop the PreallocatedMemoryThread and release its resources. - static void StopThread() { - if (the_thread_ == NULL) return; - - the_thread_->keep_running_ = false; - wait_for_ever_semaphore_->Signal(); - - // Wait for the thread to terminate. - the_thread_->Join(); - - if (data_ready_semaphore_ != NULL) { - delete data_ready_semaphore_; - data_ready_semaphore_ = NULL; - } - - delete wait_for_ever_semaphore_; - wait_for_ever_semaphore_ = NULL; - - // Done with the thread entirely. - delete the_thread_; - the_thread_ = NULL; - } - - private: - // Used to make sure that the thread keeps looping even for spurious wakeups. - bool keep_running_; - - // The preallocated memory thread singleton. - static PreallocatedMemoryThread* the_thread_; - // This semaphore is used by the PreallocatedMemoryThread to wait for ever. - static Semaphore* wait_for_ever_semaphore_; - // Semaphore to signal that the data has been initialized. - static Semaphore* data_ready_semaphore_; - - // Location and size of the preallocated memory block. - static char* data_; - static unsigned length_; - - DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread); -}; - -PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL; -Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL; -Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL; -char* PreallocatedMemoryThread::data_ = NULL; -unsigned PreallocatedMemoryThread::length_ = 0; - -static bool initialized = false; - -void Top::Initialize() { - CHECK(!initialized); - -#ifdef ENABLE_LOGGING_AND_PROFILING - ASSERT(runtime_profiler_semaphore_ == NULL); - runtime_profiler_semaphore_ = OS::CreateSemaphore(0); -#endif - - InitializeThreadLocal(); - - // Only preallocate on the first initialization. - if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) { - // Start the thread which will set aside some memory. - PreallocatedMemoryThread::StartThread(); - preallocated_message_space = - new NoAllocationStringAllocator(PreallocatedMemoryThread::data(), - PreallocatedMemoryThread::length()); - PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4); - } - initialized = true; -} - - -void Top::TearDown() { - if (initialized) { -#ifdef ENABLE_LOGGING_AND_PROFILING - delete runtime_profiler_semaphore_; - runtime_profiler_semaphore_ = NULL; -#endif - - // Remove the external reference to the preallocated stack memory. - if (preallocated_message_space != NULL) { - delete preallocated_message_space; - preallocated_message_space = NULL; - } - - PreallocatedMemoryThread::StopThread(); - initialized = false; - } -} - - -void Top::RegisterTryCatchHandler(v8::TryCatch* that) { +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 @@ -328,68 +145,64 @@ void Top::RegisterTryCatchHandler(v8::TryCatch* that) { // returned will be the address of the C++ try catch handler itself. Address address = reinterpret_cast<Address>( SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that))); - thread_local_.set_try_catch_handler_address(address); + thread_local_top()->set_try_catch_handler_address(address); } -void Top::UnregisterTryCatchHandler(v8::TryCatch* that) { - ASSERT(try_catch_handler() == that); - thread_local_.set_try_catch_handler_address( +void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) { + ASSERT(thread_local_top()->TryCatchHandler() == that); + thread_local_top()->set_try_catch_handler_address( reinterpret_cast<Address>(that->next_)); - thread_local_.catcher_ = NULL; + thread_local_top()->catcher_ = NULL; SimulatorStack::UnregisterCTryCatch(); } - -static int stack_trace_nesting_level = 0; -static StringStream* incomplete_message = NULL; - - -Handle<String> Top::StackTraceString() { - if (stack_trace_nesting_level == 0) { - stack_trace_nesting_level++; +Handle<String> Isolate::StackTraceString() { + if (stack_trace_nesting_level_ == 0) { + stack_trace_nesting_level_++; HeapStringAllocator allocator; StringStream::ClearMentionedObjectCache(); StringStream accumulator(&allocator); - incomplete_message = &accumulator; + incomplete_message_ = &accumulator; PrintStack(&accumulator); Handle<String> stack_trace = accumulator.ToString(); - incomplete_message = NULL; - stack_trace_nesting_level = 0; + incomplete_message_ = NULL; + stack_trace_nesting_level_ = 0; return stack_trace; - } else if (stack_trace_nesting_level == 1) { - stack_trace_nesting_level++; + } 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(); + incomplete_message_->OutputToStdOut(); + return factory()->empty_symbol(); } else { OS::Abort(); // Unreachable - return Factory::empty_symbol(); + return factory()->empty_symbol(); } } -Handle<JSArray> Top::CaptureCurrentStackTrace( +Handle<JSArray> Isolate::CaptureCurrentStackTrace( int frame_limit, StackTrace::StackTraceOptions options) { // Ensure no negative values. int limit = Max(frame_limit, 0); - Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit); + Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit); - Handle<String> column_key = Factory::LookupAsciiSymbol("column"); - Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber"); - Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName"); + Handle<String> column_key = factory()->LookupAsciiSymbol("column"); + Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber"); + Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName"); Handle<String> name_or_source_url_key = - Factory::LookupAsciiSymbol("nameOrSourceURL"); + factory()->LookupAsciiSymbol("nameOrSourceURL"); Handle<String> script_name_or_source_url_key = - Factory::LookupAsciiSymbol("scriptNameOrSourceURL"); - Handle<String> function_key = Factory::LookupAsciiSymbol("functionName"); - Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval"); - Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor"); + factory()->LookupAsciiSymbol("scriptNameOrSourceURL"); + Handle<String> function_key = factory()->LookupAsciiSymbol("functionName"); + Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval"); + Handle<String> constructor_key = + factory()->LookupAsciiSymbol("isConstructor"); StackTraceFrameIterator it; int frames_seen = 0; @@ -400,7 +213,7 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( 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<JSObject> stackFrame = Factory::NewJSObject(object_function()); + Handle<JSObject> stackFrame = factory()->NewJSObject(object_function()); Handle<JSFunction> fun = frames[i].function(); Handle<Script> script(Script::cast(fun->shared()->script())); @@ -429,12 +242,12 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( } if (options & StackTrace::kScriptName) { - Handle<Object> script_name(script->name()); + Handle<Object> script_name(script->name(), this); SetLocalPropertyNoThrow(stackFrame, script_key, script_name); } if (options & StackTrace::kScriptNameOrSourceURL) { - Handle<Object> script_name(script->name()); + Handle<Object> script_name(script->name(), this); Handle<JSValue> script_wrapper = GetScriptWrapper(script); Handle<Object> property = GetProperty(script_wrapper, name_or_source_url_key); @@ -444,16 +257,16 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, NULL, &caught_exception); if (caught_exception) { - result = Factory::undefined_value(); + result = factory()->undefined_value(); } SetLocalPropertyNoThrow(stackFrame, script_name_or_source_url_key, result); } if (options & StackTrace::kFunctionName) { - Handle<Object> fun_name(fun->shared()->name()); + Handle<Object> fun_name(fun->shared()->name(), this); if (fun_name->ToBoolean()->IsFalse()) { - fun_name = Handle<Object>(fun->shared()->inferred_name()); + fun_name = Handle<Object>(fun->shared()->inferred_name(), this); } SetLocalPropertyNoThrow(stackFrame, function_key, fun_name); } @@ -461,13 +274,13 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( if (options & StackTrace::kIsEval) { int type = Smi::cast(script->compilation_type())->value(); Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ? - Factory::true_value() : Factory::false_value(); + factory()->true_value() : factory()->false_value(); SetLocalPropertyNoThrow(stackFrame, eval_key, is_eval); } if (options & StackTrace::kIsConstructor) { Handle<Object> is_constructor = (frames[i].is_constructor()) ? - Factory::true_value() : Factory::false_value(); + factory()->true_value() : factory()->false_value(); SetLocalPropertyNoThrow(stackFrame, constructor_key, is_constructor); } @@ -482,41 +295,36 @@ Handle<JSArray> Top::CaptureCurrentStackTrace( } -void Top::PrintStack() { - if (stack_trace_nesting_level == 0) { - stack_trace_nesting_level++; +void Isolate::PrintStack() { + if (stack_trace_nesting_level_ == 0) { + stack_trace_nesting_level_++; StringAllocator* allocator; - if (preallocated_message_space == NULL) { + if (preallocated_message_space_ == NULL) { allocator = new HeapStringAllocator(); } else { - allocator = preallocated_message_space; + allocator = preallocated_message_space_; } - NativeAllocationChecker allocation_checker( - !FLAG_preallocate_message_memory ? - NativeAllocationChecker::ALLOW : - NativeAllocationChecker::DISALLOW); - StringStream::ClearMentionedObjectCache(); StringStream accumulator(allocator); - incomplete_message = &accumulator; + incomplete_message_ = &accumulator; PrintStack(&accumulator); accumulator.OutputToStdOut(); accumulator.Log(); - incomplete_message = NULL; - stack_trace_nesting_level = 0; - if (preallocated_message_space == NULL) { + incomplete_message_ = NULL; + stack_trace_nesting_level_ = 0; + if (preallocated_message_space_ == NULL) { // Remove the HeapStringAllocator created above. delete allocator; } - } else if (stack_trace_nesting_level == 1) { - stack_trace_nesting_level++; + } 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(); + incomplete_message_->OutputToStdOut(); } } @@ -530,13 +338,20 @@ static void PrintFrames(StringStream* accumulator, } -void Top::PrintStack(StringStream* accumulator) { +void Isolate::PrintStack(StringStream* accumulator) { + if (!IsInitialized()) { + accumulator->Add( + "\n==== Stack trace is not available ==========================\n\n"); + accumulator->Add( + "\n==== Isolate for the thread is not initialized =============\n\n"); + return; + } // The MentionedObjectCache is not GC-proof at the moment. AssertNoAllocation nogc; ASSERT(StringStream::IsMentionedObjectCacheClear()); // Avoid printing anything if there are no frames. - if (c_entry_fp(GetCurrentThread()) == 0) return; + if (c_entry_fp(thread_local_top()) == 0) return; accumulator->Add( "\n==== Stack trace ============================================\n\n"); @@ -551,28 +366,29 @@ void Top::PrintStack(StringStream* accumulator) { } -void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) { - thread_local_.failed_access_check_callback_ = callback; +void Isolate::SetFailedAccessCheckCallback( + v8::FailedAccessCheckCallback callback) { + thread_local_top()->failed_access_check_callback_ = callback; } -void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { - if (!thread_local_.failed_access_check_callback_) return; +void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) { + if (!thread_local_top()->failed_access_check_callback_) return; ASSERT(receiver->IsAccessCheckNeeded()); - ASSERT(Top::context()); + ASSERT(context()); // Get the data object from access check info. JSFunction* constructor = JSFunction::cast(receiver->map()->constructor()); if (!constructor->shared()->IsApiFunction()) return; Object* data_obj = constructor->shared()->get_api_func_data()->access_check_info(); - if (data_obj == Heap::undefined_value()) return; + if (data_obj == heap_.undefined_value()) return; HandleScope scope; Handle<JSObject> receiver_handle(receiver); Handle<Object> data(AccessCheckInfo::cast(data_obj)->data()); - thread_local_.failed_access_check_callback_( + thread_local_top()->failed_access_check_callback_( v8::Utils::ToLocal(receiver_handle), type, v8::Utils::ToLocal(data)); @@ -584,18 +400,19 @@ enum MayAccessDecision { }; -static MayAccessDecision MayAccessPreCheck(JSObject* receiver, +static MayAccessDecision MayAccessPreCheck(Isolate* isolate, + JSObject* receiver, v8::AccessType type) { // During bootstrapping, callback functions are not enabled yet. - if (Bootstrapper::IsActive()) return YES; + if (isolate->bootstrapper()->IsActive()) return YES; if (receiver->IsJSGlobalProxy()) { Object* receiver_context = JSGlobalProxy::cast(receiver)->context(); if (!receiver_context->IsContext()) return NO; // Get the global context of current top context. - // avoid using Top::global_context() because it uses Handle. - Context* global_context = Top::context()->global()->global_context(); + // avoid using Isolate::global_context() because it uses Handle. + Context* global_context = isolate->context()->global()->global_context(); if (receiver_context == global_context) return YES; if (Context::cast(receiver_context)->security_token() == @@ -607,7 +424,8 @@ static MayAccessDecision MayAccessPreCheck(JSObject* receiver, } -bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) { +bool Isolate::MayNamedAccess(JSObject* receiver, Object* key, + v8::AccessType type) { ASSERT(receiver->IsAccessCheckNeeded()); // The callers of this method are not expecting a GC. @@ -615,13 +433,13 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) { // Skip checks for hidden properties access. Note, we do not // require existence of a context in this case. - if (key == Heap::hidden_symbol()) return true; + if (key == heap_.hidden_symbol()) return true; // Check for compatibility between the security tokens in the // current lexical context and the accessed object. - ASSERT(Top::context()); + ASSERT(context()); - MayAccessDecision decision = MayAccessPreCheck(receiver, type); + MayAccessDecision decision = MayAccessPreCheck(this, receiver, type); if (decision != UNKNOWN) return decision == YES; // Get named access check callback @@ -630,7 +448,7 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) { Object* data_obj = constructor->shared()->get_api_func_data()->access_check_info(); - if (data_obj == Heap::undefined_value()) return false; + if (data_obj == heap_.undefined_value()) return false; Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback(); v8::NamedSecurityCallback callback = @@ -638,15 +456,15 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) { if (!callback) return false; - HandleScope scope; - Handle<JSObject> receiver_handle(receiver); - Handle<Object> key_handle(key); - Handle<Object> data(AccessCheckInfo::cast(data_obj)->data()); - LOG(ApiNamedSecurityCheck(key)); + HandleScope scope(this); + Handle<JSObject> receiver_handle(receiver, this); + Handle<Object> key_handle(key, this); + Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this); + LOG(this, ApiNamedSecurityCheck(key)); bool result = false; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(this, EXTERNAL); result = callback(v8::Utils::ToLocal(receiver_handle), v8::Utils::ToLocal(key_handle), type, @@ -656,17 +474,15 @@ bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) { } -bool Top::MayIndexedAccess(JSObject* receiver, - uint32_t index, - v8::AccessType type) { +bool Isolate::MayIndexedAccess(JSObject* receiver, + uint32_t index, + v8::AccessType type) { ASSERT(receiver->IsAccessCheckNeeded()); // Check for compatibility between the security tokens in the // current lexical context and the accessed object. - ASSERT(Top::context()); - // The callers of this method are not expecting a GC. - AssertNoAllocation no_gc; + ASSERT(context()); - MayAccessDecision decision = MayAccessPreCheck(receiver, type); + MayAccessDecision decision = MayAccessPreCheck(this, receiver, type); if (decision != UNKNOWN) return decision == YES; // Get indexed access check callback @@ -675,7 +491,7 @@ bool Top::MayIndexedAccess(JSObject* receiver, Object* data_obj = constructor->shared()->get_api_func_data()->access_check_info(); - if (data_obj == Heap::undefined_value()) return false; + if (data_obj == heap_.undefined_value()) return false; Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback(); v8::IndexedSecurityCallback callback = @@ -683,14 +499,14 @@ bool Top::MayIndexedAccess(JSObject* receiver, if (!callback) return false; - HandleScope scope; - Handle<JSObject> receiver_handle(receiver); - Handle<Object> data(AccessCheckInfo::cast(data_obj)->data()); - LOG(ApiIndexedSecurityCheck(index)); + HandleScope scope(this); + Handle<JSObject> receiver_handle(receiver, this); + Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this); + LOG(this, ApiIndexedSecurityCheck(index)); bool result = false; { // Leaving JavaScript. - VMState state(EXTERNAL); + VMState state(this, EXTERNAL); result = callback(v8::Utils::ToLocal(receiver_handle), index, type, @@ -700,15 +516,15 @@ bool Top::MayIndexedAccess(JSObject* receiver, } -const char* Top::kStackOverflowMessage = +const char* const Isolate::kStackOverflowMessage = "Uncaught RangeError: Maximum call stack size exceeded"; -Failure* Top::StackOverflow() { +Failure* Isolate::StackOverflow() { HandleScope scope; - Handle<String> key = Factory::stack_overflow_symbol(); + Handle<String> key = factory()->stack_overflow_symbol(); Handle<JSObject> boilerplate = - Handle<JSObject>::cast(GetProperty(Top::builtins(), key)); + Handle<JSObject>::cast(GetProperty(js_builtins_object(), key)); Handle<Object> exception = Copy(boilerplate); // TODO(1240995): To avoid having to call JavaScript code to compute // the message for stack overflow exceptions which is very likely to @@ -719,23 +535,23 @@ Failure* Top::StackOverflow() { } -Failure* Top::TerminateExecution() { - DoThrow(Heap::termination_exception(), NULL, NULL); +Failure* Isolate::TerminateExecution() { + DoThrow(heap_.termination_exception(), NULL, NULL); return Failure::Exception(); } -Failure* Top::Throw(Object* exception, MessageLocation* location) { +Failure* Isolate::Throw(Object* exception, MessageLocation* location) { DoThrow(exception, location, NULL); return Failure::Exception(); } -Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) { +Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) { bool can_be_caught_externally = false; ShouldReportException(&can_be_caught_externally, is_catchable_by_javascript(exception)); - thread_local_.catcher_ = can_be_caught_externally ? + thread_local_top()->catcher_ = can_be_caught_externally ? try_catch_handler() : NULL; // Set the exception being re-thrown. @@ -744,22 +560,22 @@ Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) { } -Failure* Top::ThrowIllegalOperation() { - return Throw(Heap::illegal_access_symbol()); +Failure* Isolate::ThrowIllegalOperation() { + return Throw(heap_.illegal_access_symbol()); } -void Top::ScheduleThrow(Object* exception) { +void Isolate::ScheduleThrow(Object* exception) { // When scheduling a throw we first throw the exception to get the // error reporting if it is uncaught before rescheduling it. Throw(exception); - thread_local_.scheduled_exception_ = pending_exception(); - thread_local_.external_caught_exception_ = false; + thread_local_top()->scheduled_exception_ = pending_exception(); + thread_local_top()->external_caught_exception_ = false; clear_pending_exception(); } -Failure* Top::PromoteScheduledException() { +Failure* Isolate::PromoteScheduledException() { MaybeObject* thrown = scheduled_exception(); clear_scheduled_exception(); // Re-throw the exception to avoid getting repeated error reporting. @@ -767,13 +583,13 @@ Failure* Top::PromoteScheduledException() { } -void Top::PrintCurrentStackTrace(FILE* out) { +void Isolate::PrintCurrentStackTrace(FILE* out) { StackTraceFrameIterator it; while (!it.done()) { HandleScope scope; // Find code position if recorded in relocation info. JavaScriptFrame* frame = it.frame(); - int pos = frame->code()->SourcePosition(frame->pc()); + int pos = frame->LookupCode(this)->SourcePosition(frame->pc()); Handle<Object> pos_obj(Smi::FromInt(pos)); // Fetch function and receiver. Handle<JSFunction> fun(JSFunction::cast(frame->function())); @@ -782,8 +598,8 @@ void Top::PrintCurrentStackTrace(FILE* out) { // current frame is the top-level frame. it.Advance(); Handle<Object> is_top_level = it.done() - ? Factory::true_value() - : Factory::false_value(); + ? factory()->true_value() + : factory()->false_value(); // Generate and print stack trace line. Handle<String> line = Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level); @@ -795,8 +611,8 @@ void Top::PrintCurrentStackTrace(FILE* out) { } -void Top::ComputeLocation(MessageLocation* target) { - *target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1); +void Isolate::ComputeLocation(MessageLocation* target) { + *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1); StackTraceFrameIterator it; if (!it.done()) { JavaScriptFrame* frame = it.frame(); @@ -804,7 +620,7 @@ void Top::ComputeLocation(MessageLocation* target) { Object* script = fun->shared()->script(); if (script->IsScript() && !(Script::cast(script)->source()->IsUndefined())) { - int pos = frame->code()->SourcePosition(frame->pc()); + int pos = frame->LookupCode(this)->SourcePosition(frame->pc()); // Compute the location from the function and the reloc info. Handle<Script> casted_script(Script::cast(script)); *target = MessageLocation(casted_script, pos, pos + 1); @@ -813,18 +629,19 @@ void Top::ComputeLocation(MessageLocation* target) { } -bool Top::ShouldReportException(bool* can_be_caught_externally, - bool catchable_by_javascript) { +bool Isolate::ShouldReportException(bool* can_be_caught_externally, + bool catchable_by_javascript) { // Find the top-most try-catch handler. StackHandler* handler = - StackHandler::FromAddress(Top::handler(Top::GetCurrentThread())); + StackHandler::FromAddress(Isolate::handler(thread_local_top())); while (handler != NULL && !handler->is_try_catch()) { handler = handler->next(); } // Get the address of the external handler so we can compare the address to // determine which one is closer to the top of the stack. - Address external_handler_address = thread_local_.try_catch_handler_address(); + Address external_handler_address = + thread_local_top()->try_catch_handler_address(); // The exception has been externally caught if and only if there is // an external handler which is on top of the top-most try-catch @@ -843,9 +660,9 @@ bool Top::ShouldReportException(bool* can_be_caught_externally, } -void Top::DoThrow(MaybeObject* exception, - MessageLocation* location, - const char* message) { +void Isolate::DoThrow(MaybeObject* exception, + MessageLocation* location, + const char* message) { ASSERT(!has_pending_exception()); HandleScope scope; @@ -865,7 +682,7 @@ void Top::DoThrow(MaybeObject* exception, #ifdef ENABLE_DEBUGGER_SUPPORT // Notify debugger of exception. if (catchable_by_javascript) { - Debugger::OnException(exception_handle, report_exception); + debugger_->OnException(exception_handle, report_exception); } #endif @@ -881,17 +698,17 @@ void Top::DoThrow(MaybeObject* exception, ComputeLocation(&potential_computed_location); location = &potential_computed_location; } - if (!Bootstrapper::IsActive()) { + if (!bootstrapper()->IsActive()) { // It's not safe to try to make message objects or collect stack // traces while the bootstrapper is active since the infrastructure // may not have been properly initialized. Handle<String> stack_trace; if (FLAG_trace_exception) stack_trace = StackTraceString(); Handle<JSArray> stack_trace_object; - if (report_exception && capture_stack_trace_for_uncaught_exceptions) { - stack_trace_object = Top::CaptureCurrentStackTrace( - stack_trace_for_uncaught_exceptions_frame_limit, - stack_trace_for_uncaught_exceptions_options); + if (report_exception && capture_stack_trace_for_uncaught_exceptions_) { + stack_trace_object = CaptureCurrentStackTrace( + stack_trace_for_uncaught_exceptions_frame_limit_, + stack_trace_for_uncaught_exceptions_options_); } ASSERT(is_object); // Can't use the handle unless there's a real object. message_obj = MessageHandler::MakeMessageObject("uncaught_exception", @@ -901,20 +718,20 @@ void Top::DoThrow(MaybeObject* exception, } // Save the message for reporting if the the exception remains uncaught. - thread_local_.has_pending_message_ = report_exception; - thread_local_.pending_message_ = message; + thread_local_top()->has_pending_message_ = report_exception; + thread_local_top()->pending_message_ = message; if (!message_obj.is_null()) { - thread_local_.pending_message_obj_ = *message_obj; + thread_local_top()->pending_message_obj_ = *message_obj; if (location != NULL) { - thread_local_.pending_message_script_ = *location->script(); - thread_local_.pending_message_start_pos_ = location->start_pos(); - thread_local_.pending_message_end_pos_ = location->end_pos(); + thread_local_top()->pending_message_script_ = *location->script(); + thread_local_top()->pending_message_start_pos_ = location->start_pos(); + thread_local_top()->pending_message_end_pos_ = location->end_pos(); } } // Do not forget to clean catcher_ if currently thrown exception cannot // be caught. If necessary, ReThrow will update the catcher. - thread_local_.catcher_ = can_be_caught_externally ? + thread_local_top()->catcher_ = can_be_caught_externally ? try_catch_handler() : NULL; // NOTE: Notifying the debugger or generating the message @@ -930,11 +747,11 @@ void Top::DoThrow(MaybeObject* exception, } -bool Top::IsExternallyCaught() { +bool Isolate::IsExternallyCaught() { ASSERT(has_pending_exception()); - if ((thread_local_.catcher_ == NULL) || - (try_catch_handler() != thread_local_.catcher_)) { + if ((thread_local_top()->catcher_ == NULL) || + (try_catch_handler() != thread_local_top()->catcher_)) { // When throwing the exception, we found no v8::TryCatch // which should care about this exception. return false; @@ -946,7 +763,8 @@ bool Top::IsExternallyCaught() { // Get the address of the external handler so we can compare the address to // determine which one is closer to the top of the stack. - Address external_handler_address = thread_local_.try_catch_handler_address(); + Address external_handler_address = + thread_local_top()->try_catch_handler_address(); ASSERT(external_handler_address != NULL); // The exception has been externally caught if and only if there is @@ -959,7 +777,7 @@ bool Top::IsExternallyCaught() { // aborted by jumps in control flow like return, break, etc. and we'll // have another chances to set proper v8::TryCatch. StackHandler* handler = - StackHandler::FromAddress(Top::handler(Top::GetCurrentThread())); + StackHandler::FromAddress(Isolate::handler(thread_local_top())); while (handler != NULL && handler->address() < external_handler_address) { ASSERT(!handler->is_try_catch()); if (handler->is_try_finally()) return false; @@ -971,46 +789,48 @@ bool Top::IsExternallyCaught() { } -void Top::ReportPendingMessages() { +void Isolate::ReportPendingMessages() { ASSERT(has_pending_exception()); // If the pending exception is OutOfMemoryException set out_of_memory in // the global context. Note: We have to mark the global context here // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to // set it. bool external_caught = IsExternallyCaught(); - thread_local_.external_caught_exception_ = external_caught; - HandleScope scope; - if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) { + thread_local_top()->external_caught_exception_ = external_caught; + HandleScope scope(this); + if (thread_local_top()->pending_exception_ == + Failure::OutOfMemoryException()) { context()->mark_out_of_memory(); - } else if (thread_local_.pending_exception_ == - Heap::termination_exception()) { + } else if (thread_local_top()->pending_exception_ == + heap_.termination_exception()) { if (external_caught) { try_catch_handler()->can_continue_ = false; - try_catch_handler()->exception_ = Heap::null_value(); + try_catch_handler()->exception_ = heap_.null_value(); } } else { // At this point all non-object (failure) exceptions have // been dealt with so this shouldn't fail. Object* pending_exception_object = pending_exception()->ToObjectUnchecked(); Handle<Object> exception(pending_exception_object); - thread_local_.external_caught_exception_ = false; + thread_local_top()->external_caught_exception_ = false; if (external_caught) { try_catch_handler()->can_continue_ = true; - try_catch_handler()->exception_ = thread_local_.pending_exception_; - if (!thread_local_.pending_message_obj_->IsTheHole()) { - try_catch_handler()->message_ = thread_local_.pending_message_obj_; + try_catch_handler()->exception_ = thread_local_top()->pending_exception_; + if (!thread_local_top()->pending_message_obj_->IsTheHole()) { + try_catch_handler()->message_ = + thread_local_top()->pending_message_obj_; } } - if (thread_local_.has_pending_message_) { - thread_local_.has_pending_message_ = false; - if (thread_local_.pending_message_ != NULL) { - MessageHandler::ReportMessage(thread_local_.pending_message_); - } else if (!thread_local_.pending_message_obj_->IsTheHole()) { - Handle<Object> message_obj(thread_local_.pending_message_obj_); - if (thread_local_.pending_message_script_ != NULL) { - Handle<Script> script(thread_local_.pending_message_script_); - int start_pos = thread_local_.pending_message_start_pos_; - int end_pos = thread_local_.pending_message_end_pos_; + if (thread_local_top()->has_pending_message_) { + thread_local_top()->has_pending_message_ = false; + if (thread_local_top()->pending_message_ != NULL) { + MessageHandler::ReportMessage(thread_local_top()->pending_message_); + } else if (!thread_local_top()->pending_message_obj_->IsTheHole()) { + Handle<Object> message_obj(thread_local_top()->pending_message_obj_); + if (thread_local_top()->pending_message_script_ != NULL) { + Handle<Script> script(thread_local_top()->pending_message_script_); + int start_pos = thread_local_top()->pending_message_start_pos_; + int end_pos = thread_local_top()->pending_message_end_pos_; MessageLocation location(script, start_pos, end_pos); MessageHandler::ReportMessage(&location, message_obj); } else { @@ -1018,40 +838,40 @@ void Top::ReportPendingMessages() { } } } - thread_local_.external_caught_exception_ = external_caught; + thread_local_top()->external_caught_exception_ = external_caught; set_pending_exception(*exception); } clear_pending_message(); } -void Top::TraceException(bool flag) { - FLAG_trace_exception = flag; +void Isolate::TraceException(bool flag) { + FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use. } -bool Top::OptionalRescheduleException(bool is_bottom_call) { +bool Isolate::OptionalRescheduleException(bool is_bottom_call) { // Allways reschedule out of memory exceptions. if (!is_out_of_memory()) { bool is_termination_exception = - pending_exception() == Heap::termination_exception(); + pending_exception() == heap_.termination_exception(); // Do not reschedule the exception if this is the bottom call. bool clear_exception = is_bottom_call; if (is_termination_exception) { if (is_bottom_call) { - thread_local_.external_caught_exception_ = false; + thread_local_top()->external_caught_exception_ = false; clear_pending_exception(); return false; } - } else if (thread_local_.external_caught_exception_) { + } else if (thread_local_top()->external_caught_exception_) { // If the exception is externally caught, clear it if there are no // JavaScript frames on the way to the C++ frame that has the // external handler. - ASSERT(thread_local_.try_catch_handler_address() != NULL); + ASSERT(thread_local_top()->try_catch_handler_address() != NULL); Address external_handler_address = - thread_local_.try_catch_handler_address(); + thread_local_top()->try_catch_handler_address(); JavaScriptFrameIterator it; if (it.done() || (it.frame()->sp() > external_handler_address)) { clear_exception = true; @@ -1060,30 +880,30 @@ bool Top::OptionalRescheduleException(bool is_bottom_call) { // Clear the exception if needed. if (clear_exception) { - thread_local_.external_caught_exception_ = false; + thread_local_top()->external_caught_exception_ = false; clear_pending_exception(); return false; } } // Reschedule the exception. - thread_local_.scheduled_exception_ = pending_exception(); + thread_local_top()->scheduled_exception_ = pending_exception(); clear_pending_exception(); return true; } -void Top::SetCaptureStackTraceForUncaughtExceptions( +void Isolate::SetCaptureStackTraceForUncaughtExceptions( bool capture, int frame_limit, StackTrace::StackTraceOptions options) { - capture_stack_trace_for_uncaught_exceptions = capture; - stack_trace_for_uncaught_exceptions_frame_limit = frame_limit; - stack_trace_for_uncaught_exceptions_options = options; + capture_stack_trace_for_uncaught_exceptions_ = capture; + stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit; + stack_trace_for_uncaught_exceptions_options_ = options; } -bool Top::is_out_of_memory() { +bool Isolate::is_out_of_memory() { if (has_pending_exception()) { MaybeObject* e = pending_exception(); if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) { @@ -1100,20 +920,20 @@ bool Top::is_out_of_memory() { } -Handle<Context> Top::global_context() { - GlobalObject* global = thread_local_.context_->global(); +Handle<Context> Isolate::global_context() { + GlobalObject* global = thread_local_top()->context_->global(); return Handle<Context>(global->global_context()); } -Handle<Context> Top::GetCallingGlobalContext() { +Handle<Context> Isolate::GetCallingGlobalContext() { JavaScriptFrameIterator it; #ifdef ENABLE_DEBUGGER_SUPPORT - if (Debug::InDebugger()) { + if (debug_->InDebugger()) { while (!it.done()) { JavaScriptFrame* frame = it.frame(); Context* context = Context::cast(frame->context()); - if (context->global_context() == *Debug::debug_context()) { + if (context->global_context() == *debug_->debug_context()) { it.Advance(); } else { break; @@ -1128,25 +948,33 @@ Handle<Context> Top::GetCallingGlobalContext() { } -char* Top::ArchiveThread(char* to) { - memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_)); +char* Isolate::ArchiveThread(char* to) { + if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) { + RuntimeProfiler::IsolateExitedJS(this); + } + memcpy(to, reinterpret_cast<char*>(thread_local_top()), + sizeof(ThreadLocalTop)); InitializeThreadLocal(); - return to + sizeof(thread_local_); + return to + sizeof(ThreadLocalTop); } -char* Top::RestoreThread(char* from) { - memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_)); +char* Isolate::RestoreThread(char* from) { + memcpy(reinterpret_cast<char*>(thread_local_top()), from, + sizeof(ThreadLocalTop)); // This might be just paranoia, but it seems to be needed in case a // thread_local_ is restored on a separate OS thread. #ifdef USE_SIMULATOR #ifdef V8_TARGET_ARCH_ARM - thread_local_.simulator_ = Simulator::current(); + thread_local_top()->simulator_ = Simulator::current(this); #elif V8_TARGET_ARCH_MIPS - thread_local_.simulator_ = assembler::mips::Simulator::current(); + thread_local_top()->simulator_ = Simulator::current(this); #endif #endif - return from + sizeof(thread_local_); + if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) { + RuntimeProfiler::IsolateEnteredJS(this); + } + return from + sizeof(ThreadLocalTop); } } } // namespace v8::internal |