Home | History | Annotate | Download | only in src
      1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #ifndef V8_TOP_H_
     29 #define V8_TOP_H_
     30 
     31 #include "frames-inl.h"
     32 
     33 namespace v8 {
     34 namespace internal {
     35 
     36 
     37 #define RETURN_IF_SCHEDULED_EXCEPTION() \
     38   if (Top::has_scheduled_exception()) return Top::PromoteScheduledException()
     39 
     40 // Top has static variables used for JavaScript execution.
     41 
     42 class SaveContext;  // Forward declaration.
     43 
     44 class ThreadLocalTop BASE_EMBEDDED {
     45  public:
     46   // Initialize the thread data.
     47   void Initialize();
     48 
     49   // Get the top C++ try catch handler or NULL if none are registered.
     50   //
     51   // This method is not guarenteed to return an address that can be
     52   // used for comparison with addresses into the JS stack.  If such an
     53   // address is needed, use try_catch_handler_address.
     54   v8::TryCatch* TryCatchHandler();
     55 
     56   // Get the address of the top C++ try catch handler or NULL if
     57   // none are registered.
     58   //
     59   // This method always returns an address that can be compared to
     60   // pointers into the JavaScript stack.  When running on actual
     61   // hardware, try_catch_handler_address and TryCatchHandler return
     62   // the same pointer.  When running on a simulator with a separate JS
     63   // stack, try_catch_handler_address returns a JS stack address that
     64   // corresponds to the place on the JS stack where the C++ handler
     65   // would have been if the stack were not separate.
     66   inline Address try_catch_handler_address() {
     67     return try_catch_handler_address_;
     68   }
     69 
     70   // Set the address of the top C++ try catch handler.
     71   inline void set_try_catch_handler_address(Address address) {
     72     try_catch_handler_address_ = address;
     73   }
     74 
     75   void Free() {
     76     ASSERT(!has_pending_message_);
     77     ASSERT(!external_caught_exception_);
     78     ASSERT(try_catch_handler_address_ == NULL);
     79   }
     80 
     81   // The context where the current execution method is created and for variable
     82   // lookups.
     83   Context* context_;
     84   int thread_id_;
     85   Object* pending_exception_;
     86   bool has_pending_message_;
     87   const char* pending_message_;
     88   Object* pending_message_obj_;
     89   Script* pending_message_script_;
     90   int pending_message_start_pos_;
     91   int pending_message_end_pos_;
     92   // Use a separate value for scheduled exceptions to preserve the
     93   // invariants that hold about pending_exception.  We may want to
     94   // unify them later.
     95   Object* scheduled_exception_;
     96   bool external_caught_exception_;
     97   SaveContext* save_context_;
     98   v8::TryCatch* catcher_;
     99 
    100   // Stack.
    101   Address c_entry_fp_;  // the frame pointer of the top c entry frame
    102   Address handler_;   // try-blocks are chained through the stack
    103 #ifdef ENABLE_LOGGING_AND_PROFILING
    104   Address js_entry_sp_;  // the stack pointer of the bottom js entry frame
    105 #endif
    106   bool stack_is_cooked_;
    107   inline bool stack_is_cooked() { return stack_is_cooked_; }
    108   inline void set_stack_is_cooked(bool value) { stack_is_cooked_ = value; }
    109 
    110   // Generated code scratch locations.
    111   int32_t formal_count_;
    112 
    113   // Call back function to report unsafe JS accesses.
    114   v8::FailedAccessCheckCallback failed_access_check_callback_;
    115 
    116  private:
    117   Address try_catch_handler_address_;
    118 };
    119 
    120 #define TOP_ADDRESS_LIST(C)            \
    121   C(handler_address)                   \
    122   C(c_entry_fp_address)                \
    123   C(context_address)                   \
    124   C(pending_exception_address)         \
    125   C(external_caught_exception_address)
    126 
    127 #ifdef ENABLE_LOGGING_AND_PROFILING
    128 #define TOP_ADDRESS_LIST_PROF(C)       \
    129   C(js_entry_sp_address)
    130 #else
    131 #define TOP_ADDRESS_LIST_PROF(C)
    132 #endif
    133 
    134 
    135 class Top {
    136  public:
    137   enum AddressId {
    138 #define C(name) k_##name,
    139     TOP_ADDRESS_LIST(C)
    140     TOP_ADDRESS_LIST_PROF(C)
    141 #undef C
    142     k_top_address_count
    143   };
    144 
    145   static Address get_address_from_id(AddressId id);
    146 
    147   // Access to top context (where the current function object was created).
    148   static Context* context() { return thread_local_.context_; }
    149   static void set_context(Context* context) {
    150     thread_local_.context_ = context;
    151   }
    152   static Context** context_address() { return &thread_local_.context_; }
    153 
    154   static SaveContext* save_context() {return thread_local_.save_context_; }
    155   static void set_save_context(SaveContext* save) {
    156     thread_local_.save_context_ = save;
    157   }
    158 
    159   // Access to current thread id.
    160   static int thread_id() { return thread_local_.thread_id_; }
    161   static void set_thread_id(int id) { thread_local_.thread_id_ = id; }
    162 
    163   // Interface to pending exception.
    164   static Object* pending_exception() {
    165     ASSERT(has_pending_exception());
    166     return thread_local_.pending_exception_;
    167   }
    168   static bool external_caught_exception() {
    169     return thread_local_.external_caught_exception_;
    170   }
    171   static void set_pending_exception(Object* exception) {
    172     thread_local_.pending_exception_ = exception;
    173   }
    174   static void clear_pending_exception() {
    175     thread_local_.pending_exception_ = Heap::the_hole_value();
    176   }
    177 
    178   static Object** pending_exception_address() {
    179     return &thread_local_.pending_exception_;
    180   }
    181   static bool has_pending_exception() {
    182     return !thread_local_.pending_exception_->IsTheHole();
    183   }
    184   static void clear_pending_message() {
    185     thread_local_.has_pending_message_ = false;
    186     thread_local_.pending_message_ = NULL;
    187     thread_local_.pending_message_obj_ = Heap::the_hole_value();
    188     thread_local_.pending_message_script_ = NULL;
    189   }
    190   static v8::TryCatch* try_catch_handler() {
    191     return thread_local_.TryCatchHandler();
    192   }
    193   static Address try_catch_handler_address() {
    194     return thread_local_.try_catch_handler_address();
    195   }
    196   // This method is called by the api after operations that may throw
    197   // exceptions.  If an exception was thrown and not handled by an external
    198   // handler the exception is scheduled to be rethrown when we return to running
    199   // JavaScript code.  If an exception is scheduled true is returned.
    200   static bool OptionalRescheduleException(bool is_bottom_call);
    201 
    202 
    203   static bool* external_caught_exception_address() {
    204     return &thread_local_.external_caught_exception_;
    205   }
    206 
    207   static Object** scheduled_exception_address() {
    208     return &thread_local_.scheduled_exception_;
    209   }
    210 
    211   static Object* scheduled_exception() {
    212     ASSERT(has_scheduled_exception());
    213     return thread_local_.scheduled_exception_;
    214   }
    215   static bool has_scheduled_exception() {
    216     return !thread_local_.scheduled_exception_->IsTheHole();
    217   }
    218   static void clear_scheduled_exception() {
    219     thread_local_.scheduled_exception_ = Heap::the_hole_value();
    220   }
    221 
    222   static void setup_external_caught() {
    223     thread_local_.external_caught_exception_ =
    224         has_pending_exception() &&
    225         (thread_local_.catcher_ != NULL) &&
    226         (try_catch_handler() == thread_local_.catcher_);
    227   }
    228 
    229   // Tells whether the current context has experienced an out of memory
    230   // exception.
    231   static bool is_out_of_memory();
    232 
    233   // JS execution stack (see frames.h).
    234   static Address c_entry_fp(ThreadLocalTop* thread) {
    235     return thread->c_entry_fp_;
    236   }
    237   static Address handler(ThreadLocalTop* thread) { return thread->handler_; }
    238 
    239   static inline Address* c_entry_fp_address() {
    240     return &thread_local_.c_entry_fp_;
    241   }
    242   static inline Address* handler_address() { return &thread_local_.handler_; }
    243 
    244 #ifdef ENABLE_LOGGING_AND_PROFILING
    245   // Bottom JS entry (see StackTracer::Trace in log.cc).
    246   static Address js_entry_sp(ThreadLocalTop* thread) {
    247     return thread->js_entry_sp_;
    248   }
    249   static inline Address* js_entry_sp_address() {
    250     return &thread_local_.js_entry_sp_;
    251   }
    252 #endif
    253 
    254   // Generated code scratch locations.
    255   static void* formal_count_address() { return &thread_local_.formal_count_; }
    256 
    257   static void MarkCompactPrologue(bool is_compacting);
    258   static void MarkCompactEpilogue(bool is_compacting);
    259   static void MarkCompactPrologue(bool is_compacting,
    260                                   char* archived_thread_data);
    261   static void MarkCompactEpilogue(bool is_compacting,
    262                                   char* archived_thread_data);
    263   static void PrintCurrentStackTrace(FILE* out);
    264   static void PrintStackTrace(FILE* out, char* thread_data);
    265   static void PrintStack(StringStream* accumulator);
    266   static void PrintStack();
    267   static Handle<String> StackTrace();
    268 
    269   // Returns if the top context may access the given global object. If
    270   // the result is false, the pending exception is guaranteed to be
    271   // set.
    272   static bool MayNamedAccess(JSObject* receiver,
    273                              Object* key,
    274                              v8::AccessType type);
    275   static bool MayIndexedAccess(JSObject* receiver,
    276                                uint32_t index,
    277                                v8::AccessType type);
    278 
    279   static void SetFailedAccessCheckCallback(
    280       v8::FailedAccessCheckCallback callback);
    281   static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type);
    282 
    283   // Exception throwing support. The caller should use the result
    284   // of Throw() as its return value.
    285   static Failure* Throw(Object* exception, MessageLocation* location = NULL);
    286   // Re-throw an exception.  This involves no error reporting since
    287   // error reporting was handled when the exception was thrown
    288   // originally.
    289   static Failure* ReThrow(Object* exception, MessageLocation* location = NULL);
    290   static void ScheduleThrow(Object* exception);
    291   static void ReportPendingMessages();
    292   static Failure* ThrowIllegalOperation();
    293 
    294   // Promote a scheduled exception to pending. Asserts has_scheduled_exception.
    295   static Object* PromoteScheduledException();
    296   static void DoThrow(Object* exception,
    297                       MessageLocation* location,
    298                       const char* message);
    299   static bool ShouldReturnException(bool* is_caught_externally,
    300                                     bool catchable_by_javascript);
    301   static void ReportUncaughtException(Handle<Object> exception,
    302                                       MessageLocation* location,
    303                                       Handle<String> stack_trace);
    304 
    305   // Attempts to compute the current source location, storing the
    306   // result in the target out parameter.
    307   static void ComputeLocation(MessageLocation* target);
    308 
    309   // Override command line flag.
    310   static void TraceException(bool flag);
    311 
    312   // Out of resource exception helpers.
    313   static Failure* StackOverflow();
    314   static Failure* TerminateExecution();
    315 
    316   // Administration
    317   static void Initialize();
    318   static void TearDown();
    319   static void Iterate(ObjectVisitor* v);
    320   static void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
    321   static char* Iterate(ObjectVisitor* v, char* t);
    322 
    323   // Returns the global object of the current context. It could be
    324   // a builtin object, or a js global object.
    325   static Handle<GlobalObject> global() {
    326     return Handle<GlobalObject>(context()->global());
    327   }
    328 
    329   // Returns the global proxy object of the current context.
    330   static Object* global_proxy() {
    331     return context()->global_proxy();
    332   }
    333 
    334   // Returns the current global context.
    335   static Handle<Context> global_context();
    336 
    337   // Returns the global context of the calling JavaScript code.  That
    338   // is, the global context of the top-most JavaScript frame.
    339   static Handle<Context> GetCallingGlobalContext();
    340 
    341   static Handle<JSBuiltinsObject> builtins() {
    342     return Handle<JSBuiltinsObject>(thread_local_.context_->builtins());
    343   }
    344 
    345   static bool CanHaveSpecialFunctions(JSObject* object);
    346   static Object* LookupSpecialFunction(JSObject* receiver,
    347                                        JSObject* prototype,
    348                                        JSFunction* value);
    349 
    350   static void RegisterTryCatchHandler(v8::TryCatch* that);
    351   static void UnregisterTryCatchHandler(v8::TryCatch* that);
    352 
    353 #define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name)  \
    354   static Handle<type> name() {                                \
    355     return Handle<type>(context()->global_context()->name()); \
    356   }
    357   GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR)
    358 #undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR
    359 
    360   static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; }
    361   static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); }
    362   static char* ArchiveThread(char* to);
    363   static char* RestoreThread(char* from);
    364   static void FreeThreadResources() { thread_local_.Free(); }
    365 
    366   static const char* kStackOverflowMessage;
    367 
    368  private:
    369   // The context that initiated this JS execution.
    370   static ThreadLocalTop thread_local_;
    371   static void InitializeThreadLocal();
    372   static void PrintStackTrace(FILE* out, ThreadLocalTop* thread);
    373   static void MarkCompactPrologue(bool is_compacting,
    374                                   ThreadLocalTop* archived_thread_data);
    375   static void MarkCompactEpilogue(bool is_compacting,
    376                                   ThreadLocalTop* archived_thread_data);
    377 
    378   // Debug.
    379   // Mutex for serializing access to break control structures.
    380   static Mutex* break_access_;
    381 
    382   friend class SaveContext;
    383   friend class AssertNoContextChange;
    384   friend class ExecutionAccess;
    385 
    386   static void FillCache();
    387 };
    388 
    389 
    390 // If the GCC version is 4.1.x or 4.2.x an additional field is added to the
    391 // class as a work around for a bug in the generated code found with these
    392 // versions of GCC. See V8 issue 122 for details.
    393 class SaveContext BASE_EMBEDDED {
    394  public:
    395   SaveContext()
    396       : context_(Top::context()),
    397 #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
    398         dummy_(Top::context()),
    399 #endif
    400         prev_(Top::save_context()) {
    401     Top::set_save_context(this);
    402 
    403     // If there is no JS frame under the current C frame, use the value 0.
    404     JavaScriptFrameIterator it;
    405     js_sp_ = it.done() ? 0 : it.frame()->sp();
    406   }
    407 
    408   ~SaveContext() {
    409     Top::set_context(*context_);
    410     Top::set_save_context(prev_);
    411   }
    412 
    413   Handle<Context> context() { return context_; }
    414   SaveContext* prev() { return prev_; }
    415 
    416   // Returns true if this save context is below a given JavaScript frame.
    417   bool below(JavaScriptFrame* frame) {
    418     return (js_sp_ == 0) || (frame->sp() < js_sp_);
    419   }
    420 
    421  private:
    422   Handle<Context> context_;
    423 #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300
    424   Handle<Context> dummy_;
    425 #endif
    426   SaveContext* prev_;
    427   Address js_sp_;  // The top JS frame's sp when saving context.
    428 };
    429 
    430 
    431 class AssertNoContextChange BASE_EMBEDDED {
    432 #ifdef DEBUG
    433  public:
    434   AssertNoContextChange() :
    435       context_(Top::context()) {
    436   }
    437 
    438   ~AssertNoContextChange() {
    439     ASSERT(Top::context() == *context_);
    440   }
    441 
    442  private:
    443   HandleScope scope_;
    444   Handle<Context> context_;
    445 #else
    446  public:
    447   AssertNoContextChange() { }
    448 #endif
    449 };
    450 
    451 
    452 class ExecutionAccess BASE_EMBEDDED {
    453  public:
    454   ExecutionAccess();
    455   ~ExecutionAccess();
    456 };
    457 
    458 } }  // namespace v8::internal
    459 
    460 #endif  // V8_TOP_H_
    461