ager@chromium.org | 9258b6b | 2008-09-11 09:11:10 +0000 | [diff] [blame] | 1 | // Copyright 2006-2008 the V8 project authors. All rights reserved. |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 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 | |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 31 | #include "atomicops.h" |
| 32 | #include "compilation-cache.h" |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 33 | #include "frames-inl.h" |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 34 | #include "runtime-profiler.h" |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 35 | |
kasperl@chromium.org | 71affb5 | 2009-05-26 05:44:31 +0000 | [diff] [blame] | 36 | namespace v8 { |
| 37 | namespace internal { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 38 | |
ricow@chromium.org | 83aa549 | 2011-02-07 12:42:56 +0000 | [diff] [blame] | 39 | class Simulator; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 40 | |
| 41 | #define RETURN_IF_SCHEDULED_EXCEPTION() \ |
| 42 | if (Top::has_scheduled_exception()) return Top::PromoteScheduledException() |
| 43 | |
| 44 | // Top has static variables used for JavaScript execution. |
| 45 | |
ager@chromium.org | 3291210 | 2009-01-16 10:38:43 +0000 | [diff] [blame] | 46 | class SaveContext; // Forward declaration. |
whesse@chromium.org | cec079d | 2010-03-22 14:44:04 +0000 | [diff] [blame] | 47 | class ThreadVisitor; // Defined in v8threads.h |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 48 | class VMState; // Defined in vm-state.h |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 49 | |
| 50 | class ThreadLocalTop BASE_EMBEDDED { |
| 51 | public: |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 52 | // Initialize the thread data. |
| 53 | void Initialize(); |
| 54 | |
| 55 | // Get the top C++ try catch handler or NULL if none are registered. |
| 56 | // |
| 57 | // This method is not guarenteed to return an address that can be |
| 58 | // used for comparison with addresses into the JS stack. If such an |
| 59 | // address is needed, use try_catch_handler_address. |
| 60 | v8::TryCatch* TryCatchHandler(); |
| 61 | |
| 62 | // Get the address of the top C++ try catch handler or NULL if |
| 63 | // none are registered. |
| 64 | // |
| 65 | // This method always returns an address that can be compared to |
| 66 | // pointers into the JavaScript stack. When running on actual |
| 67 | // hardware, try_catch_handler_address and TryCatchHandler return |
| 68 | // the same pointer. When running on a simulator with a separate JS |
| 69 | // stack, try_catch_handler_address returns a JS stack address that |
| 70 | // corresponds to the place on the JS stack where the C++ handler |
| 71 | // would have been if the stack were not separate. |
| 72 | inline Address try_catch_handler_address() { |
| 73 | return try_catch_handler_address_; |
| 74 | } |
| 75 | |
| 76 | // Set the address of the top C++ try catch handler. |
| 77 | inline void set_try_catch_handler_address(Address address) { |
| 78 | try_catch_handler_address_ = address; |
| 79 | } |
| 80 | |
| 81 | void Free() { |
| 82 | ASSERT(!has_pending_message_); |
| 83 | ASSERT(!external_caught_exception_); |
| 84 | ASSERT(try_catch_handler_address_ == NULL); |
| 85 | } |
| 86 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 87 | // The context where the current execution method is created and for variable |
| 88 | // lookups. |
| 89 | Context* context_; |
sgjesse@chromium.org | c81c894 | 2009-08-21 10:54:26 +0000 | [diff] [blame] | 90 | int thread_id_; |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 91 | MaybeObject* pending_exception_; |
ager@chromium.org | 8bb6058 | 2008-12-11 12:02:20 +0000 | [diff] [blame] | 92 | bool has_pending_message_; |
| 93 | const char* pending_message_; |
| 94 | Object* pending_message_obj_; |
| 95 | Script* pending_message_script_; |
| 96 | int pending_message_start_pos_; |
| 97 | int pending_message_end_pos_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 98 | // Use a separate value for scheduled exceptions to preserve the |
| 99 | // invariants that hold about pending_exception. We may want to |
| 100 | // unify them later. |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 101 | MaybeObject* scheduled_exception_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 102 | bool external_caught_exception_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 103 | SaveContext* save_context_; |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 104 | v8::TryCatch* catcher_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 105 | |
| 106 | // Stack. |
| 107 | Address c_entry_fp_; // the frame pointer of the top c entry frame |
| 108 | Address handler_; // try-blocks are chained through the stack |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 109 | |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 110 | #ifdef USE_SIMULATOR |
fschneider@chromium.org | e03fb64 | 2010-11-01 12:34:09 +0000 | [diff] [blame] | 111 | #ifdef V8_TARGET_ARCH_ARM |
ager@chromium.org | 378b34e | 2011-01-28 08:04:38 +0000 | [diff] [blame] | 112 | Simulator* simulator_; |
fschneider@chromium.org | e03fb64 | 2010-11-01 12:34:09 +0000 | [diff] [blame] | 113 | #elif V8_TARGET_ARCH_MIPS |
| 114 | assembler::mips::Simulator* simulator_; |
| 115 | #endif |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 116 | #endif // USE_SIMULATOR |
| 117 | |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 118 | #ifdef ENABLE_LOGGING_AND_PROFILING |
| 119 | Address js_entry_sp_; // the stack pointer of the bottom js entry frame |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 120 | Address external_callback_; // the external callback we're currently in |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 121 | #endif |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 122 | |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 123 | #ifdef ENABLE_VMSTATE_TRACKING |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 124 | StateTag current_vm_state_; |
| 125 | |
| 126 | // Used for communication with the runtime profiler thread. |
| 127 | // Possible values are specified in RuntimeProfilerState. |
| 128 | Atomic32 runtime_profiler_state_; |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 129 | #endif |
| 130 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 131 | // Generated code scratch locations. |
| 132 | int32_t formal_count_; |
| 133 | |
| 134 | // Call back function to report unsafe JS accesses. |
| 135 | v8::FailedAccessCheckCallback failed_access_check_callback_; |
sgjesse@chromium.org | c514574 | 2009-10-07 09:00:33 +0000 | [diff] [blame] | 136 | |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 137 | private: |
| 138 | Address try_catch_handler_address_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 139 | }; |
| 140 | |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 141 | #define TOP_ADDRESS_LIST(C) \ |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 142 | C(handler_address) \ |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 143 | C(c_entry_fp_address) \ |
| 144 | C(context_address) \ |
| 145 | C(pending_exception_address) \ |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 146 | C(external_caught_exception_address) |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 147 | |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 148 | #ifdef ENABLE_LOGGING_AND_PROFILING |
| 149 | #define TOP_ADDRESS_LIST_PROF(C) \ |
| 150 | C(js_entry_sp_address) |
| 151 | #else |
| 152 | #define TOP_ADDRESS_LIST_PROF(C) |
| 153 | #endif |
| 154 | |
| 155 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 156 | class Top { |
| 157 | public: |
| 158 | enum AddressId { |
| 159 | #define C(name) k_##name, |
| 160 | TOP_ADDRESS_LIST(C) |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 161 | TOP_ADDRESS_LIST_PROF(C) |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 162 | #undef C |
| 163 | k_top_address_count |
| 164 | }; |
| 165 | |
| 166 | static Address get_address_from_id(AddressId id); |
| 167 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 168 | // Access to top context (where the current function object was created). |
| 169 | static Context* context() { return thread_local_.context_; } |
| 170 | static void set_context(Context* context) { |
| 171 | thread_local_.context_ = context; |
| 172 | } |
| 173 | static Context** context_address() { return &thread_local_.context_; } |
| 174 | |
| 175 | static SaveContext* save_context() {return thread_local_.save_context_; } |
| 176 | static void set_save_context(SaveContext* save) { |
| 177 | thread_local_.save_context_ = save; |
| 178 | } |
| 179 | |
sgjesse@chromium.org | c81c894 | 2009-08-21 10:54:26 +0000 | [diff] [blame] | 180 | // Access to current thread id. |
| 181 | static int thread_id() { return thread_local_.thread_id_; } |
| 182 | static void set_thread_id(int id) { thread_local_.thread_id_ = id; } |
| 183 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 184 | // Interface to pending exception. |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 185 | static MaybeObject* pending_exception() { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 186 | ASSERT(has_pending_exception()); |
| 187 | return thread_local_.pending_exception_; |
| 188 | } |
| 189 | static bool external_caught_exception() { |
| 190 | return thread_local_.external_caught_exception_; |
| 191 | } |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 192 | static void set_pending_exception(MaybeObject* exception) { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 193 | thread_local_.pending_exception_ = exception; |
| 194 | } |
| 195 | static void clear_pending_exception() { |
| 196 | thread_local_.pending_exception_ = Heap::the_hole_value(); |
| 197 | } |
| 198 | |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 199 | static MaybeObject** pending_exception_address() { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 200 | return &thread_local_.pending_exception_; |
| 201 | } |
| 202 | static bool has_pending_exception() { |
| 203 | return !thread_local_.pending_exception_->IsTheHole(); |
| 204 | } |
ager@chromium.org | 8bb6058 | 2008-12-11 12:02:20 +0000 | [diff] [blame] | 205 | static void clear_pending_message() { |
ager@chromium.org | 8bb6058 | 2008-12-11 12:02:20 +0000 | [diff] [blame] | 206 | thread_local_.has_pending_message_ = false; |
| 207 | thread_local_.pending_message_ = NULL; |
| 208 | thread_local_.pending_message_obj_ = Heap::the_hole_value(); |
| 209 | thread_local_.pending_message_script_ = NULL; |
| 210 | } |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 211 | static v8::TryCatch* try_catch_handler() { |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 212 | return thread_local_.TryCatchHandler(); |
| 213 | } |
| 214 | static Address try_catch_handler_address() { |
| 215 | return thread_local_.try_catch_handler_address(); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 216 | } |
| 217 | // This method is called by the api after operations that may throw |
| 218 | // exceptions. If an exception was thrown and not handled by an external |
| 219 | // handler the exception is scheduled to be rethrown when we return to running |
| 220 | // JavaScript code. If an exception is scheduled true is returned. |
ager@chromium.org | 18ad94b | 2009-09-02 08:22:29 +0000 | [diff] [blame] | 221 | static bool OptionalRescheduleException(bool is_bottom_call); |
| 222 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 223 | |
| 224 | static bool* external_caught_exception_address() { |
| 225 | return &thread_local_.external_caught_exception_; |
| 226 | } |
| 227 | |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 228 | static MaybeObject** scheduled_exception_address() { |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 229 | return &thread_local_.scheduled_exception_; |
| 230 | } |
| 231 | |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 232 | static MaybeObject* scheduled_exception() { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 233 | ASSERT(has_scheduled_exception()); |
| 234 | return thread_local_.scheduled_exception_; |
| 235 | } |
| 236 | static bool has_scheduled_exception() { |
| 237 | return !thread_local_.scheduled_exception_->IsTheHole(); |
| 238 | } |
| 239 | static void clear_scheduled_exception() { |
| 240 | thread_local_.scheduled_exception_ = Heap::the_hole_value(); |
| 241 | } |
| 242 | |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 243 | static void setup_external_caught() { |
ager@chromium.org | 3a6061e | 2009-03-12 14:24:36 +0000 | [diff] [blame] | 244 | thread_local_.external_caught_exception_ = |
ager@chromium.org | 71daaf6 | 2009-04-01 07:22:49 +0000 | [diff] [blame] | 245 | has_pending_exception() && |
ager@chromium.org | 3a6061e | 2009-03-12 14:24:36 +0000 | [diff] [blame] | 246 | (thread_local_.catcher_ != NULL) && |
ager@chromium.org | c4c9272 | 2009-11-18 14:12:51 +0000 | [diff] [blame] | 247 | (try_catch_handler() == thread_local_.catcher_); |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 248 | } |
| 249 | |
ager@chromium.org | 6a2b0aa | 2010-07-13 20:58:03 +0000 | [diff] [blame] | 250 | static void SetCaptureStackTraceForUncaughtExceptions( |
| 251 | bool capture, |
| 252 | int frame_limit, |
| 253 | StackTrace::StackTraceOptions options); |
| 254 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 255 | // Tells whether the current context has experienced an out of memory |
| 256 | // exception. |
| 257 | static bool is_out_of_memory(); |
| 258 | |
| 259 | // JS execution stack (see frames.h). |
| 260 | static Address c_entry_fp(ThreadLocalTop* thread) { |
| 261 | return thread->c_entry_fp_; |
| 262 | } |
| 263 | static Address handler(ThreadLocalTop* thread) { return thread->handler_; } |
| 264 | |
| 265 | static inline Address* c_entry_fp_address() { |
| 266 | return &thread_local_.c_entry_fp_; |
| 267 | } |
| 268 | static inline Address* handler_address() { return &thread_local_.handler_; } |
| 269 | |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 270 | #ifdef ENABLE_LOGGING_AND_PROFILING |
| 271 | // Bottom JS entry (see StackTracer::Trace in log.cc). |
| 272 | static Address js_entry_sp(ThreadLocalTop* thread) { |
| 273 | return thread->js_entry_sp_; |
| 274 | } |
| 275 | static inline Address* js_entry_sp_address() { |
| 276 | return &thread_local_.js_entry_sp_; |
| 277 | } |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 278 | |
| 279 | static Address external_callback() { |
| 280 | return thread_local_.external_callback_; |
| 281 | } |
| 282 | static void set_external_callback(Address callback) { |
| 283 | thread_local_.external_callback_ = callback; |
| 284 | } |
ager@chromium.org | e2902be | 2009-06-08 12:21:35 +0000 | [diff] [blame] | 285 | #endif |
| 286 | |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 287 | #ifdef ENABLE_VMSTATE_TRACKING |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 288 | static StateTag current_vm_state() { |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 289 | return thread_local_.current_vm_state_; |
| 290 | } |
| 291 | |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 292 | static void SetCurrentVMState(StateTag state) { |
| 293 | if (RuntimeProfiler::IsEnabled()) { |
| 294 | if (state == JS) { |
| 295 | // JS or non-JS -> JS transition. |
| 296 | RuntimeProfilerState old_state = SwapRuntimeProfilerState(PROF_IN_JS); |
| 297 | if (old_state == PROF_NOT_IN_JS_WAITING_FOR_JS) { |
| 298 | // If the runtime profiler was waiting, we reset the eager |
| 299 | // optimizing data in the compilation cache to get a fresh |
| 300 | // start after not running JavaScript code for a while and |
| 301 | // signal the runtime profiler so it can resume. |
| 302 | CompilationCache::ResetEagerOptimizingData(); |
| 303 | runtime_profiler_semaphore_->Signal(); |
| 304 | } |
| 305 | } else if (thread_local_.current_vm_state_ == JS) { |
| 306 | // JS -> non-JS transition. Update the runtime profiler state. |
| 307 | ASSERT(IsInJSState()); |
| 308 | SetRuntimeProfilerState(PROF_NOT_IN_JS); |
| 309 | } |
| 310 | } |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 311 | thread_local_.current_vm_state_ = state; |
| 312 | } |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 313 | |
| 314 | // Called in the runtime profiler thread. |
| 315 | // Returns whether the current VM state is set to JS. |
| 316 | static bool IsInJSState() { |
| 317 | ASSERT(RuntimeProfiler::IsEnabled()); |
| 318 | return static_cast<RuntimeProfilerState>( |
| 319 | NoBarrier_Load(&thread_local_.runtime_profiler_state_)) == PROF_IN_JS; |
| 320 | } |
| 321 | |
| 322 | // Called in the runtime profiler thread. |
| 323 | // Waits for the VM state to transtion from non-JS to JS. Returns |
| 324 | // true when notified of the transition, false when the current |
| 325 | // state is not the expected non-JS state. |
| 326 | static bool WaitForJSState() { |
| 327 | ASSERT(RuntimeProfiler::IsEnabled()); |
| 328 | // Try to switch to waiting state. |
| 329 | RuntimeProfilerState old_state = CompareAndSwapRuntimeProfilerState( |
| 330 | PROF_NOT_IN_JS, PROF_NOT_IN_JS_WAITING_FOR_JS); |
| 331 | if (old_state == PROF_NOT_IN_JS) { |
| 332 | runtime_profiler_semaphore_->Wait(); |
| 333 | return true; |
| 334 | } |
| 335 | return false; |
| 336 | } |
| 337 | |
| 338 | // When shutting down we join the profiler thread. Doing so while |
| 339 | // it's waiting on a semaphore will cause a deadlock, so we have to |
| 340 | // wake it up first. |
| 341 | static void WakeUpRuntimeProfilerThreadBeforeShutdown() { |
| 342 | runtime_profiler_semaphore_->Signal(); |
| 343 | } |
whesse@chromium.org | 4a5224e | 2010-10-20 12:37:07 +0000 | [diff] [blame] | 344 | #endif |
| 345 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 346 | // Generated code scratch locations. |
| 347 | static void* formal_count_address() { return &thread_local_.formal_count_; } |
| 348 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 349 | static void PrintCurrentStackTrace(FILE* out); |
| 350 | static void PrintStackTrace(FILE* out, char* thread_data); |
| 351 | static void PrintStack(StringStream* accumulator); |
| 352 | static void PrintStack(); |
sgjesse@chromium.org | 720dc0b | 2010-05-10 09:25:39 +0000 | [diff] [blame] | 353 | static Handle<String> StackTraceString(); |
ager@chromium.org | 6a2b0aa | 2010-07-13 20:58:03 +0000 | [diff] [blame] | 354 | static Handle<JSArray> CaptureCurrentStackTrace( |
sgjesse@chromium.org | 720dc0b | 2010-05-10 09:25:39 +0000 | [diff] [blame] | 355 | int frame_limit, |
| 356 | StackTrace::StackTraceOptions options); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 357 | |
| 358 | // Returns if the top context may access the given global object. If |
| 359 | // the result is false, the pending exception is guaranteed to be |
| 360 | // set. |
| 361 | static bool MayNamedAccess(JSObject* receiver, |
| 362 | Object* key, |
| 363 | v8::AccessType type); |
| 364 | static bool MayIndexedAccess(JSObject* receiver, |
| 365 | uint32_t index, |
| 366 | v8::AccessType type); |
| 367 | |
| 368 | static void SetFailedAccessCheckCallback( |
| 369 | v8::FailedAccessCheckCallback callback); |
| 370 | static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); |
| 371 | |
| 372 | // Exception throwing support. The caller should use the result |
| 373 | // of Throw() as its return value. |
| 374 | static Failure* Throw(Object* exception, MessageLocation* location = NULL); |
| 375 | // Re-throw an exception. This involves no error reporting since |
| 376 | // error reporting was handled when the exception was thrown |
| 377 | // originally. |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 378 | static Failure* ReThrow(MaybeObject* exception, |
| 379 | MessageLocation* location = NULL); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 380 | static void ScheduleThrow(Object* exception); |
ager@chromium.org | 8bb6058 | 2008-12-11 12:02:20 +0000 | [diff] [blame] | 381 | static void ReportPendingMessages(); |
ager@chromium.org | 3e87580 | 2009-06-29 08:26:34 +0000 | [diff] [blame] | 382 | static Failure* ThrowIllegalOperation(); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 383 | |
| 384 | // Promote a scheduled exception to pending. Asserts has_scheduled_exception. |
lrn@chromium.org | 303ada7 | 2010-10-27 09:33:13 +0000 | [diff] [blame] | 385 | static Failure* PromoteScheduledException(); |
| 386 | static void DoThrow(MaybeObject* exception, |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 387 | MessageLocation* location, |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 388 | const char* message); |
ager@chromium.org | 378b34e | 2011-01-28 08:04:38 +0000 | [diff] [blame] | 389 | // Checks if exception should be reported and finds out if it's |
| 390 | // caught externally. |
| 391 | static bool ShouldReportException(bool* is_caught_externally, |
sgjesse@chromium.org | c81c894 | 2009-08-21 10:54:26 +0000 | [diff] [blame] | 392 | bool catchable_by_javascript); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 393 | |
ager@chromium.org | 9258b6b | 2008-09-11 09:11:10 +0000 | [diff] [blame] | 394 | // Attempts to compute the current source location, storing the |
| 395 | // result in the target out parameter. |
| 396 | static void ComputeLocation(MessageLocation* target); |
| 397 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 398 | // Override command line flag. |
| 399 | static void TraceException(bool flag); |
| 400 | |
| 401 | // Out of resource exception helpers. |
| 402 | static Failure* StackOverflow(); |
sgjesse@chromium.org | c81c894 | 2009-08-21 10:54:26 +0000 | [diff] [blame] | 403 | static Failure* TerminateExecution(); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 404 | |
| 405 | // Administration |
| 406 | static void Initialize(); |
kasper.lund | af4734f | 2008-07-28 12:50:18 +0000 | [diff] [blame] | 407 | static void TearDown(); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 408 | static void Iterate(ObjectVisitor* v); |
| 409 | static void Iterate(ObjectVisitor* v, ThreadLocalTop* t); |
| 410 | static char* Iterate(ObjectVisitor* v, char* t); |
whesse@chromium.org | cec079d | 2010-03-22 14:44:04 +0000 | [diff] [blame] | 411 | static void IterateThread(ThreadVisitor* v); |
| 412 | static void IterateThread(ThreadVisitor* v, char* t); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 413 | |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 414 | // Returns the global object of the current context. It could be |
| 415 | // a builtin object, or a js global object. |
| 416 | static Handle<GlobalObject> global() { |
| 417 | return Handle<GlobalObject>(context()->global()); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 418 | } |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 419 | |
| 420 | // Returns the global proxy object of the current context. |
| 421 | static Object* global_proxy() { |
| 422 | return context()->global_proxy(); |
| 423 | } |
| 424 | |
ager@chromium.org | 1bf0cd0 | 2009-05-20 11:34:19 +0000 | [diff] [blame] | 425 | // Returns the current global context. |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 426 | static Handle<Context> global_context(); |
| 427 | |
ager@chromium.org | 1bf0cd0 | 2009-05-20 11:34:19 +0000 | [diff] [blame] | 428 | // Returns the global context of the calling JavaScript code. That |
| 429 | // is, the global context of the top-most JavaScript frame. |
| 430 | static Handle<Context> GetCallingGlobalContext(); |
| 431 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 432 | static Handle<JSBuiltinsObject> builtins() { |
| 433 | return Handle<JSBuiltinsObject>(thread_local_.context_->builtins()); |
| 434 | } |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 435 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 436 | static void RegisterTryCatchHandler(v8::TryCatch* that); |
| 437 | static void UnregisterTryCatchHandler(v8::TryCatch* that); |
| 438 | |
| 439 | #define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name) \ |
| 440 | static Handle<type> name() { \ |
| 441 | return Handle<type>(context()->global_context()->name()); \ |
| 442 | } |
| 443 | GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR) |
| 444 | #undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR |
| 445 | |
| 446 | static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; } |
| 447 | static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); } |
| 448 | static char* ArchiveThread(char* to); |
| 449 | static char* RestoreThread(char* from); |
sgjesse@chromium.org | c514574 | 2009-10-07 09:00:33 +0000 | [diff] [blame] | 450 | static void FreeThreadResources() { thread_local_.Free(); } |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 451 | |
ager@chromium.org | a74f0da | 2008-12-03 16:05:52 +0000 | [diff] [blame] | 452 | static const char* kStackOverflowMessage; |
| 453 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 454 | private: |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 455 | #ifdef ENABLE_VMSTATE_TRACKING |
| 456 | // Set of states used when communicating with the runtime profiler. |
| 457 | // |
| 458 | // The set of possible transitions is divided between the VM and the |
| 459 | // profiler threads. |
| 460 | // |
| 461 | // The VM thread can perform these transitions: |
| 462 | // o IN_JS -> NOT_IN_JS |
| 463 | // o NOT_IN_JS -> IN_JS |
| 464 | // o NOT_IN_JS_WAITING_FOR_JS -> IN_JS notifying the profiler thread |
| 465 | // using the semaphore. |
| 466 | // All the above transitions are caused by VM state changes. |
| 467 | // |
| 468 | // The profiler thread can only perform a single transition |
| 469 | // NOT_IN_JS -> NOT_IN_JS_WAITING_FOR_JS before it starts waiting on |
| 470 | // the semaphore. |
| 471 | enum RuntimeProfilerState { |
| 472 | PROF_NOT_IN_JS, |
| 473 | PROF_NOT_IN_JS_WAITING_FOR_JS, |
| 474 | PROF_IN_JS |
| 475 | }; |
| 476 | |
| 477 | static void SetRuntimeProfilerState(RuntimeProfilerState state) { |
| 478 | NoBarrier_Store(&thread_local_.runtime_profiler_state_, state); |
| 479 | } |
| 480 | |
| 481 | static RuntimeProfilerState SwapRuntimeProfilerState( |
| 482 | RuntimeProfilerState state) { |
| 483 | return static_cast<RuntimeProfilerState>( |
| 484 | NoBarrier_AtomicExchange(&thread_local_.runtime_profiler_state_, |
| 485 | state)); |
| 486 | } |
| 487 | |
| 488 | static RuntimeProfilerState CompareAndSwapRuntimeProfilerState( |
| 489 | RuntimeProfilerState old_state, |
| 490 | RuntimeProfilerState state) { |
| 491 | return static_cast<RuntimeProfilerState>( |
| 492 | NoBarrier_CompareAndSwap(&thread_local_.runtime_profiler_state_, |
| 493 | old_state, |
| 494 | state)); |
| 495 | } |
| 496 | |
| 497 | static Semaphore* runtime_profiler_semaphore_; |
| 498 | #endif // ENABLE_VMSTATE_TRACKING |
| 499 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 500 | // The context that initiated this JS execution. |
| 501 | static ThreadLocalTop thread_local_; |
| 502 | static void InitializeThreadLocal(); |
| 503 | static void PrintStackTrace(FILE* out, ThreadLocalTop* thread); |
kasperl@chromium.org | 061ef74 | 2009-02-27 12:16:20 +0000 | [diff] [blame] | 504 | static void MarkCompactPrologue(bool is_compacting, |
| 505 | ThreadLocalTop* archived_thread_data); |
| 506 | static void MarkCompactEpilogue(bool is_compacting, |
| 507 | ThreadLocalTop* archived_thread_data); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 508 | |
| 509 | // Debug. |
| 510 | // Mutex for serializing access to break control structures. |
| 511 | static Mutex* break_access_; |
| 512 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 513 | friend class SaveContext; |
| 514 | friend class AssertNoContextChange; |
| 515 | friend class ExecutionAccess; |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 516 | friend class ThreadLocalTop; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 517 | |
| 518 | static void FillCache(); |
| 519 | }; |
| 520 | |
| 521 | |
kasperl@chromium.org | 9fe21c6 | 2008-10-28 08:53:51 +0000 | [diff] [blame] | 522 | // If the GCC version is 4.1.x or 4.2.x an additional field is added to the |
ager@chromium.org | 3291210 | 2009-01-16 10:38:43 +0000 | [diff] [blame] | 523 | // class as a work around for a bug in the generated code found with these |
kasperl@chromium.org | 9fe21c6 | 2008-10-28 08:53:51 +0000 | [diff] [blame] | 524 | // versions of GCC. See V8 issue 122 for details. |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 525 | class SaveContext BASE_EMBEDDED { |
| 526 | public: |
kasperl@chromium.org | 7be3c99 | 2009-03-12 07:19:55 +0000 | [diff] [blame] | 527 | SaveContext() |
| 528 | : context_(Top::context()), |
kasperl@chromium.org | 9fe21c6 | 2008-10-28 08:53:51 +0000 | [diff] [blame] | 529 | #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 |
kasperl@chromium.org | 7be3c99 | 2009-03-12 07:19:55 +0000 | [diff] [blame] | 530 | dummy_(Top::context()), |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 531 | #endif |
kasperl@chromium.org | 7be3c99 | 2009-03-12 07:19:55 +0000 | [diff] [blame] | 532 | prev_(Top::save_context()) { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 533 | Top::set_save_context(this); |
ager@chromium.org | a74f0da | 2008-12-03 16:05:52 +0000 | [diff] [blame] | 534 | |
| 535 | // If there is no JS frame under the current C frame, use the value 0. |
| 536 | JavaScriptFrameIterator it; |
| 537 | js_sp_ = it.done() ? 0 : it.frame()->sp(); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 538 | } |
| 539 | |
| 540 | ~SaveContext() { |
| 541 | Top::set_context(*context_); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 542 | Top::set_save_context(prev_); |
| 543 | } |
| 544 | |
| 545 | Handle<Context> context() { return context_; } |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 546 | SaveContext* prev() { return prev_; } |
| 547 | |
ager@chromium.org | a74f0da | 2008-12-03 16:05:52 +0000 | [diff] [blame] | 548 | // Returns true if this save context is below a given JavaScript frame. |
| 549 | bool below(JavaScriptFrame* frame) { |
| 550 | return (js_sp_ == 0) || (frame->sp() < js_sp_); |
| 551 | } |
| 552 | |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 553 | private: |
| 554 | Handle<Context> context_; |
kasperl@chromium.org | 9fe21c6 | 2008-10-28 08:53:51 +0000 | [diff] [blame] | 555 | #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 556 | Handle<Context> dummy_; |
| 557 | #endif |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 558 | SaveContext* prev_; |
ager@chromium.org | a74f0da | 2008-12-03 16:05:52 +0000 | [diff] [blame] | 559 | Address js_sp_; // The top JS frame's sp when saving context. |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 560 | }; |
| 561 | |
| 562 | |
| 563 | class AssertNoContextChange BASE_EMBEDDED { |
| 564 | #ifdef DEBUG |
| 565 | public: |
| 566 | AssertNoContextChange() : |
kasperl@chromium.org | 5a8ca6c | 2008-10-23 13:57:19 +0000 | [diff] [blame] | 567 | context_(Top::context()) { |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 568 | } |
| 569 | |
| 570 | ~AssertNoContextChange() { |
| 571 | ASSERT(Top::context() == *context_); |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 572 | } |
| 573 | |
| 574 | private: |
| 575 | HandleScope scope_; |
| 576 | Handle<Context> context_; |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 577 | #else |
| 578 | public: |
| 579 | AssertNoContextChange() { } |
| 580 | #endif |
| 581 | }; |
| 582 | |
| 583 | |
| 584 | class ExecutionAccess BASE_EMBEDDED { |
| 585 | public: |
kasperl@chromium.org | a555126 | 2010-12-07 12:49:48 +0000 | [diff] [blame] | 586 | ExecutionAccess() { Lock(); } |
| 587 | ~ExecutionAccess() { Unlock(); } |
| 588 | |
| 589 | static void Lock() { Top::break_access_->Lock(); } |
| 590 | static void Unlock() { Top::break_access_->Unlock(); } |
| 591 | |
| 592 | static bool TryLock() { |
| 593 | return Top::break_access_->TryLock(); |
| 594 | } |
christian.plesner.hansen | 43d26ec | 2008-07-03 15:10:15 +0000 | [diff] [blame] | 595 | }; |
| 596 | |
| 597 | } } // namespace v8::internal |
| 598 | |
| 599 | #endif // V8_TOP_H_ |