Index: src/top.h |
=================================================================== |
--- src/top.h (revision 7267) |
+++ src/top.h (working copy) |
@@ -1,608 +0,0 @@ |
-// 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. |
- |
-#ifndef V8_TOP_H_ |
-#define V8_TOP_H_ |
- |
-#include "atomicops.h" |
-#include "compilation-cache.h" |
-#include "frames-inl.h" |
-#include "runtime-profiler.h" |
- |
-namespace v8 { |
-namespace internal { |
- |
-class Simulator; |
- |
-#define RETURN_IF_SCHEDULED_EXCEPTION() \ |
- if (Top::has_scheduled_exception()) return Top::PromoteScheduledException() |
- |
-#define RETURN_IF_EMPTY_HANDLE_VALUE(call, value) \ |
- if (call.is_null()) { \ |
- ASSERT(Top::has_pending_exception()); \ |
- return value; \ |
- } |
- |
-#define RETURN_IF_EMPTY_HANDLE(call) \ |
- RETURN_IF_EMPTY_HANDLE_VALUE(call, Failure::Exception()) |
- |
-// Top has static variables used for JavaScript execution. |
- |
-class SaveContext; // Forward declaration. |
-class ThreadVisitor; // Defined in v8threads.h |
-class VMState; // Defined in vm-state.h |
- |
-class ThreadLocalTop BASE_EMBEDDED { |
- public: |
- // Initialize the thread data. |
- void Initialize(); |
- |
- // Get the top C++ try catch handler or NULL if none are registered. |
- // |
- // This method is not guarenteed to return an address that can be |
- // used for comparison with addresses into the JS stack. If such an |
- // address is needed, use try_catch_handler_address. |
- v8::TryCatch* TryCatchHandler(); |
- |
- // Get the address of the top C++ try catch handler or NULL if |
- // none are registered. |
- // |
- // This method always returns an address that can be compared to |
- // pointers into the JavaScript stack. When running on actual |
- // hardware, try_catch_handler_address and TryCatchHandler return |
- // the same pointer. When running on a simulator with a separate JS |
- // stack, try_catch_handler_address returns a JS stack address that |
- // corresponds to the place on the JS stack where the C++ handler |
- // would have been if the stack were not separate. |
- inline Address try_catch_handler_address() { |
- return try_catch_handler_address_; |
- } |
- |
- // Set the address of the top C++ try catch handler. |
- inline void set_try_catch_handler_address(Address address) { |
- try_catch_handler_address_ = address; |
- } |
- |
- void Free() { |
- ASSERT(!has_pending_message_); |
- ASSERT(!external_caught_exception_); |
- ASSERT(try_catch_handler_address_ == NULL); |
- } |
- |
- // The context where the current execution method is created and for variable |
- // lookups. |
- Context* context_; |
- int thread_id_; |
- MaybeObject* pending_exception_; |
- bool has_pending_message_; |
- const char* pending_message_; |
- Object* pending_message_obj_; |
- Script* pending_message_script_; |
- int pending_message_start_pos_; |
- int pending_message_end_pos_; |
- // Use a separate value for scheduled exceptions to preserve the |
- // invariants that hold about pending_exception. We may want to |
- // unify them later. |
- MaybeObject* scheduled_exception_; |
- bool external_caught_exception_; |
- SaveContext* save_context_; |
- v8::TryCatch* catcher_; |
- |
- // Stack. |
- Address c_entry_fp_; // the frame pointer of the top c entry frame |
- Address handler_; // try-blocks are chained through the stack |
- |
-#ifdef USE_SIMULATOR |
-#ifdef V8_TARGET_ARCH_ARM |
- Simulator* simulator_; |
-#elif V8_TARGET_ARCH_MIPS |
- assembler::mips::Simulator* simulator_; |
-#endif |
-#endif // USE_SIMULATOR |
- |
-#ifdef ENABLE_LOGGING_AND_PROFILING |
- Address js_entry_sp_; // the stack pointer of the bottom js entry frame |
- Address external_callback_; // the external callback we're currently in |
-#endif |
- |
-#ifdef ENABLE_VMSTATE_TRACKING |
- StateTag current_vm_state_; |
- |
- // Used for communication with the runtime profiler thread. |
- // Possible values are specified in RuntimeProfilerState. |
- Atomic32 runtime_profiler_state_; |
-#endif |
- |
- // Generated code scratch locations. |
- int32_t formal_count_; |
- |
- // Call back function to report unsafe JS accesses. |
- v8::FailedAccessCheckCallback failed_access_check_callback_; |
- |
- private: |
- Address try_catch_handler_address_; |
-}; |
- |
-#define TOP_ADDRESS_LIST(C) \ |
- C(handler_address) \ |
- C(c_entry_fp_address) \ |
- C(context_address) \ |
- C(pending_exception_address) \ |
- C(external_caught_exception_address) |
- |
-#ifdef ENABLE_LOGGING_AND_PROFILING |
-#define TOP_ADDRESS_LIST_PROF(C) \ |
- C(js_entry_sp_address) |
-#else |
-#define TOP_ADDRESS_LIST_PROF(C) |
-#endif |
- |
- |
-class Top { |
- public: |
- enum AddressId { |
-#define C(name) k_##name, |
- TOP_ADDRESS_LIST(C) |
- TOP_ADDRESS_LIST_PROF(C) |
-#undef C |
- k_top_address_count |
- }; |
- |
- static Address get_address_from_id(AddressId id); |
- |
- // Access to top context (where the current function object was created). |
- static Context* context() { return thread_local_.context_; } |
- static void set_context(Context* context) { |
- thread_local_.context_ = context; |
- } |
- static Context** context_address() { return &thread_local_.context_; } |
- |
- static SaveContext* save_context() {return thread_local_.save_context_; } |
- static void set_save_context(SaveContext* save) { |
- thread_local_.save_context_ = save; |
- } |
- |
- // Access to current thread id. |
- static int thread_id() { return thread_local_.thread_id_; } |
- static void set_thread_id(int id) { thread_local_.thread_id_ = id; } |
- |
- // Interface to pending exception. |
- static MaybeObject* pending_exception() { |
- ASSERT(has_pending_exception()); |
- return thread_local_.pending_exception_; |
- } |
- static bool external_caught_exception() { |
- return thread_local_.external_caught_exception_; |
- } |
- static void set_pending_exception(MaybeObject* exception) { |
- thread_local_.pending_exception_ = exception; |
- } |
- static void clear_pending_exception() { |
- thread_local_.pending_exception_ = Heap::the_hole_value(); |
- } |
- |
- static MaybeObject** pending_exception_address() { |
- return &thread_local_.pending_exception_; |
- } |
- static bool has_pending_exception() { |
- return !thread_local_.pending_exception_->IsTheHole(); |
- } |
- static void clear_pending_message() { |
- thread_local_.has_pending_message_ = false; |
- thread_local_.pending_message_ = NULL; |
- thread_local_.pending_message_obj_ = Heap::the_hole_value(); |
- thread_local_.pending_message_script_ = NULL; |
- } |
- static v8::TryCatch* try_catch_handler() { |
- return thread_local_.TryCatchHandler(); |
- } |
- static Address try_catch_handler_address() { |
- return thread_local_.try_catch_handler_address(); |
- } |
- // This method is called by the api after operations that may throw |
- // exceptions. If an exception was thrown and not handled by an external |
- // handler the exception is scheduled to be rethrown when we return to running |
- // JavaScript code. If an exception is scheduled true is returned. |
- static bool OptionalRescheduleException(bool is_bottom_call); |
- |
- |
- static bool* external_caught_exception_address() { |
- return &thread_local_.external_caught_exception_; |
- } |
- |
- static MaybeObject** scheduled_exception_address() { |
- return &thread_local_.scheduled_exception_; |
- } |
- |
- static MaybeObject* scheduled_exception() { |
- ASSERT(has_scheduled_exception()); |
- return thread_local_.scheduled_exception_; |
- } |
- static bool has_scheduled_exception() { |
- return !thread_local_.scheduled_exception_->IsTheHole(); |
- } |
- static void clear_scheduled_exception() { |
- thread_local_.scheduled_exception_ = Heap::the_hole_value(); |
- } |
- |
- static bool IsExternallyCaught(); |
- |
- static void SetCaptureStackTraceForUncaughtExceptions( |
- bool capture, |
- int frame_limit, |
- StackTrace::StackTraceOptions options); |
- |
- // Tells whether the current context has experienced an out of memory |
- // exception. |
- static bool is_out_of_memory(); |
- |
- static bool is_catchable_by_javascript(MaybeObject* exception) { |
- return (exception != Failure::OutOfMemoryException()) && |
- (exception != Heap::termination_exception()); |
- } |
- |
- // JS execution stack (see frames.h). |
- static Address c_entry_fp(ThreadLocalTop* thread) { |
- return thread->c_entry_fp_; |
- } |
- static Address handler(ThreadLocalTop* thread) { return thread->handler_; } |
- |
- static inline Address* c_entry_fp_address() { |
- return &thread_local_.c_entry_fp_; |
- } |
- static inline Address* handler_address() { return &thread_local_.handler_; } |
- |
-#ifdef ENABLE_LOGGING_AND_PROFILING |
- // Bottom JS entry (see StackTracer::Trace in log.cc). |
- static Address js_entry_sp(ThreadLocalTop* thread) { |
- return thread->js_entry_sp_; |
- } |
- static inline Address* js_entry_sp_address() { |
- return &thread_local_.js_entry_sp_; |
- } |
- |
- static Address external_callback() { |
- return thread_local_.external_callback_; |
- } |
- static void set_external_callback(Address callback) { |
- thread_local_.external_callback_ = callback; |
- } |
-#endif |
- |
-#ifdef ENABLE_VMSTATE_TRACKING |
- static StateTag current_vm_state() { |
- return thread_local_.current_vm_state_; |
- } |
- |
- static void SetCurrentVMState(StateTag state) { |
- if (RuntimeProfiler::IsEnabled()) { |
- if (state == JS) { |
- // JS or non-JS -> JS transition. |
- RuntimeProfilerState old_state = SwapRuntimeProfilerState(PROF_IN_JS); |
- if (old_state == PROF_NOT_IN_JS_WAITING_FOR_JS) { |
- // If the runtime profiler was waiting, we reset the eager |
- // optimizing data in the compilation cache to get a fresh |
- // start after not running JavaScript code for a while and |
- // signal the runtime profiler so it can resume. |
- CompilationCache::ResetEagerOptimizingData(); |
- runtime_profiler_semaphore_->Signal(); |
- } |
- } else if (thread_local_.current_vm_state_ == JS) { |
- // JS -> non-JS transition. Update the runtime profiler state. |
- ASSERT(IsInJSState()); |
- SetRuntimeProfilerState(PROF_NOT_IN_JS); |
- } |
- } |
- thread_local_.current_vm_state_ = state; |
- } |
- |
- // Called in the runtime profiler thread. |
- // Returns whether the current VM state is set to JS. |
- static bool IsInJSState() { |
- ASSERT(RuntimeProfiler::IsEnabled()); |
- return static_cast<RuntimeProfilerState>( |
- NoBarrier_Load(&thread_local_.runtime_profiler_state_)) == PROF_IN_JS; |
- } |
- |
- // Called in the runtime profiler thread. |
- // Waits for the VM state to transtion from non-JS to JS. Returns |
- // true when notified of the transition, false when the current |
- // state is not the expected non-JS state. |
- static bool WaitForJSState() { |
- ASSERT(RuntimeProfiler::IsEnabled()); |
- // Try to switch to waiting state. |
- RuntimeProfilerState old_state = CompareAndSwapRuntimeProfilerState( |
- PROF_NOT_IN_JS, PROF_NOT_IN_JS_WAITING_FOR_JS); |
- if (old_state == PROF_NOT_IN_JS) { |
- runtime_profiler_semaphore_->Wait(); |
- return true; |
- } |
- return false; |
- } |
- |
- // When shutting down we join the profiler thread. Doing so while |
- // it's waiting on a semaphore will cause a deadlock, so we have to |
- // wake it up first. |
- static void WakeUpRuntimeProfilerThreadBeforeShutdown() { |
- runtime_profiler_semaphore_->Signal(); |
- } |
-#endif |
- |
- // Generated code scratch locations. |
- static void* formal_count_address() { return &thread_local_.formal_count_; } |
- |
- static void PrintCurrentStackTrace(FILE* out); |
- static void PrintStackTrace(FILE* out, char* thread_data); |
- static void PrintStack(StringStream* accumulator); |
- static void PrintStack(); |
- static Handle<String> StackTraceString(); |
- static Handle<JSArray> CaptureCurrentStackTrace( |
- int frame_limit, |
- StackTrace::StackTraceOptions options); |
- |
- // Returns if the top context may access the given global object. If |
- // the result is false, the pending exception is guaranteed to be |
- // set. |
- static bool MayNamedAccess(JSObject* receiver, |
- Object* key, |
- v8::AccessType type); |
- static bool MayIndexedAccess(JSObject* receiver, |
- uint32_t index, |
- v8::AccessType type); |
- |
- static void SetFailedAccessCheckCallback( |
- v8::FailedAccessCheckCallback callback); |
- static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); |
- |
- // Exception throwing support. The caller should use the result |
- // of Throw() as its return value. |
- static Failure* Throw(Object* exception, MessageLocation* location = NULL); |
- // Re-throw an exception. This involves no error reporting since |
- // error reporting was handled when the exception was thrown |
- // originally. |
- static Failure* ReThrow(MaybeObject* exception, |
- MessageLocation* location = NULL); |
- static void ScheduleThrow(Object* exception); |
- static void ReportPendingMessages(); |
- static Failure* ThrowIllegalOperation(); |
- |
- // Promote a scheduled exception to pending. Asserts has_scheduled_exception. |
- static Failure* PromoteScheduledException(); |
- static void DoThrow(MaybeObject* exception, |
- MessageLocation* location, |
- const char* message); |
- // Checks if exception should be reported and finds out if it's |
- // caught externally. |
- static bool ShouldReportException(bool* can_be_caught_externally, |
- bool catchable_by_javascript); |
- |
- // Attempts to compute the current source location, storing the |
- // result in the target out parameter. |
- static void ComputeLocation(MessageLocation* target); |
- |
- // Override command line flag. |
- static void TraceException(bool flag); |
- |
- // Out of resource exception helpers. |
- static Failure* StackOverflow(); |
- static Failure* TerminateExecution(); |
- |
- // Administration |
- static void Initialize(); |
- static void TearDown(); |
- static void Iterate(ObjectVisitor* v); |
- static void Iterate(ObjectVisitor* v, ThreadLocalTop* t); |
- static char* Iterate(ObjectVisitor* v, char* t); |
- static void IterateThread(ThreadVisitor* v); |
- static void IterateThread(ThreadVisitor* v, char* t); |
- |
- // Returns the global object of the current context. It could be |
- // a builtin object, or a js global object. |
- static Handle<GlobalObject> global() { |
- return Handle<GlobalObject>(context()->global()); |
- } |
- |
- // Returns the global proxy object of the current context. |
- static Object* global_proxy() { |
- return context()->global_proxy(); |
- } |
- |
- // Returns the current global context. |
- static Handle<Context> global_context(); |
- |
- // Returns the global context of the calling JavaScript code. That |
- // is, the global context of the top-most JavaScript frame. |
- static Handle<Context> GetCallingGlobalContext(); |
- |
- static Handle<JSBuiltinsObject> builtins() { |
- return Handle<JSBuiltinsObject>(thread_local_.context_->builtins()); |
- } |
- |
- static void RegisterTryCatchHandler(v8::TryCatch* that); |
- static void UnregisterTryCatchHandler(v8::TryCatch* that); |
- |
-#define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name) \ |
- static Handle<type> name() { \ |
- return Handle<type>(context()->global_context()->name()); \ |
- } |
- GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR) |
-#undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR |
- |
- static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; } |
- static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); } |
- static char* ArchiveThread(char* to); |
- static char* RestoreThread(char* from); |
- static void FreeThreadResources() { thread_local_.Free(); } |
- |
- static const char* kStackOverflowMessage; |
- |
- private: |
-#ifdef ENABLE_VMSTATE_TRACKING |
- // Set of states used when communicating with the runtime profiler. |
- // |
- // The set of possible transitions is divided between the VM and the |
- // profiler threads. |
- // |
- // The VM thread can perform these transitions: |
- // o IN_JS -> NOT_IN_JS |
- // o NOT_IN_JS -> IN_JS |
- // o NOT_IN_JS_WAITING_FOR_JS -> IN_JS notifying the profiler thread |
- // using the semaphore. |
- // All the above transitions are caused by VM state changes. |
- // |
- // The profiler thread can only perform a single transition |
- // NOT_IN_JS -> NOT_IN_JS_WAITING_FOR_JS before it starts waiting on |
- // the semaphore. |
- enum RuntimeProfilerState { |
- PROF_NOT_IN_JS, |
- PROF_NOT_IN_JS_WAITING_FOR_JS, |
- PROF_IN_JS |
- }; |
- |
- static void SetRuntimeProfilerState(RuntimeProfilerState state) { |
- NoBarrier_Store(&thread_local_.runtime_profiler_state_, state); |
- } |
- |
- static RuntimeProfilerState SwapRuntimeProfilerState( |
- RuntimeProfilerState state) { |
- return static_cast<RuntimeProfilerState>( |
- NoBarrier_AtomicExchange(&thread_local_.runtime_profiler_state_, |
- state)); |
- } |
- |
- static RuntimeProfilerState CompareAndSwapRuntimeProfilerState( |
- RuntimeProfilerState old_state, |
- RuntimeProfilerState state) { |
- return static_cast<RuntimeProfilerState>( |
- NoBarrier_CompareAndSwap(&thread_local_.runtime_profiler_state_, |
- old_state, |
- state)); |
- } |
- |
- static Semaphore* runtime_profiler_semaphore_; |
-#endif // ENABLE_VMSTATE_TRACKING |
- |
- // The context that initiated this JS execution. |
- static ThreadLocalTop thread_local_; |
- static void InitializeThreadLocal(); |
- static void PrintStackTrace(FILE* out, ThreadLocalTop* thread); |
- static void MarkCompactPrologue(bool is_compacting, |
- ThreadLocalTop* archived_thread_data); |
- static void MarkCompactEpilogue(bool is_compacting, |
- ThreadLocalTop* archived_thread_data); |
- |
- // Debug. |
- // Mutex for serializing access to break control structures. |
- static Mutex* break_access_; |
- |
- friend class SaveContext; |
- friend class AssertNoContextChange; |
- friend class ExecutionAccess; |
- friend class ThreadLocalTop; |
- |
- static void FillCache(); |
-}; |
- |
- |
-// If the GCC version is 4.1.x or 4.2.x an additional field is added to the |
-// class as a work around for a bug in the generated code found with these |
-// versions of GCC. See V8 issue 122 for details. |
-class SaveContext BASE_EMBEDDED { |
- public: |
- SaveContext() |
- : context_(Top::context()), |
-#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 |
- dummy_(Top::context()), |
-#endif |
- prev_(Top::save_context()) { |
- Top::set_save_context(this); |
- |
- // If there is no JS frame under the current C frame, use the value 0. |
- JavaScriptFrameIterator it; |
- js_sp_ = it.done() ? 0 : it.frame()->sp(); |
- } |
- |
- ~SaveContext() { |
- Top::set_context(*context_); |
- Top::set_save_context(prev_); |
- } |
- |
- Handle<Context> context() { return context_; } |
- SaveContext* prev() { return prev_; } |
- |
- // Returns true if this save context is below a given JavaScript frame. |
- bool below(JavaScriptFrame* frame) { |
- return (js_sp_ == 0) || (frame->sp() < js_sp_); |
- } |
- |
- private: |
- Handle<Context> context_; |
-#if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 |
- Handle<Context> dummy_; |
-#endif |
- SaveContext* prev_; |
- Address js_sp_; // The top JS frame's sp when saving context. |
-}; |
- |
- |
-class AssertNoContextChange BASE_EMBEDDED { |
-#ifdef DEBUG |
- public: |
- AssertNoContextChange() : |
- context_(Top::context()) { |
- } |
- |
- ~AssertNoContextChange() { |
- ASSERT(Top::context() == *context_); |
- } |
- |
- private: |
- HandleScope scope_; |
- Handle<Context> context_; |
-#else |
- public: |
- AssertNoContextChange() { } |
-#endif |
-}; |
- |
- |
-class ExecutionAccess BASE_EMBEDDED { |
- public: |
- ExecutionAccess() { Lock(); } |
- ~ExecutionAccess() { Unlock(); } |
- |
- static void Lock() { Top::break_access_->Lock(); } |
- static void Unlock() { Top::break_access_->Unlock(); } |
- |
- static bool TryLock() { |
- return Top::break_access_->TryLock(); |
- } |
-}; |
- |
-} } // namespace v8::internal |
- |
-#endif // V8_TOP_H_ |