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