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. try_catch_handler_address()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. set_try_catch_handler_address(Address address)71 inline void set_try_catch_handler_address(Address address) { 72 try_catch_handler_address_ = address; 73 } 74 Free()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_; stack_is_cooked()107 inline bool stack_is_cooked() { return stack_is_cooked_; } set_stack_is_cooked(bool value)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). context()148 static Context* context() { return thread_local_.context_; } set_context(Context * context)149 static void set_context(Context* context) { 150 thread_local_.context_ = context; 151 } context_address()152 static Context** context_address() { return &thread_local_.context_; } 153 save_context()154 static SaveContext* save_context() {return thread_local_.save_context_; } set_save_context(SaveContext * save)155 static void set_save_context(SaveContext* save) { 156 thread_local_.save_context_ = save; 157 } 158 159 // Access to current thread id. thread_id()160 static int thread_id() { return thread_local_.thread_id_; } set_thread_id(int id)161 static void set_thread_id(int id) { thread_local_.thread_id_ = id; } 162 163 // Interface to pending exception. pending_exception()164 static Object* pending_exception() { 165 ASSERT(has_pending_exception()); 166 return thread_local_.pending_exception_; 167 } external_caught_exception()168 static bool external_caught_exception() { 169 return thread_local_.external_caught_exception_; 170 } set_pending_exception(Object * exception)171 static void set_pending_exception(Object* exception) { 172 thread_local_.pending_exception_ = exception; 173 } clear_pending_exception()174 static void clear_pending_exception() { 175 thread_local_.pending_exception_ = Heap::the_hole_value(); 176 } 177 pending_exception_address()178 static Object** pending_exception_address() { 179 return &thread_local_.pending_exception_; 180 } has_pending_exception()181 static bool has_pending_exception() { 182 return !thread_local_.pending_exception_->IsTheHole(); 183 } clear_pending_message()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 } try_catch_handler()190 static v8::TryCatch* try_catch_handler() { 191 return thread_local_.TryCatchHandler(); 192 } try_catch_handler_address()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 external_caught_exception_address()203 static bool* external_caught_exception_address() { 204 return &thread_local_.external_caught_exception_; 205 } 206 scheduled_exception_address()207 static Object** scheduled_exception_address() { 208 return &thread_local_.scheduled_exception_; 209 } 210 scheduled_exception()211 static Object* scheduled_exception() { 212 ASSERT(has_scheduled_exception()); 213 return thread_local_.scheduled_exception_; 214 } has_scheduled_exception()215 static bool has_scheduled_exception() { 216 return !thread_local_.scheduled_exception_->IsTheHole(); 217 } clear_scheduled_exception()218 static void clear_scheduled_exception() { 219 thread_local_.scheduled_exception_ = Heap::the_hole_value(); 220 } 221 setup_external_caught()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). c_entry_fp(ThreadLocalTop * thread)234 static Address c_entry_fp(ThreadLocalTop* thread) { 235 return thread->c_entry_fp_; 236 } handler(ThreadLocalTop * thread)237 static Address handler(ThreadLocalTop* thread) { return thread->handler_; } 238 c_entry_fp_address()239 static inline Address* c_entry_fp_address() { 240 return &thread_local_.c_entry_fp_; 241 } handler_address()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). js_entry_sp(ThreadLocalTop * thread)246 static Address js_entry_sp(ThreadLocalTop* thread) { 247 return thread->js_entry_sp_; 248 } js_entry_sp_address()249 static inline Address* js_entry_sp_address() { 250 return &thread_local_.js_entry_sp_; 251 } 252 #endif 253 254 // Generated code scratch locations. formal_count_address()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. global()325 static Handle<GlobalObject> global() { 326 return Handle<GlobalObject>(context()->global()); 327 } 328 329 // Returns the global proxy object of the current context. global_proxy()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 builtins()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 } GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR)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_; } ArchiveSpacePerThread()361 static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); } 362 static char* ArchiveThread(char* to); 363 static char* RestoreThread(char* from); FreeThreadResources()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: SaveContext()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 ~SaveContext()408 ~SaveContext() { 409 Top::set_context(*context_); 410 Top::set_save_context(prev_); 411 } 412 context()413 Handle<Context> context() { return context_; } prev()414 SaveContext* prev() { return prev_; } 415 416 // Returns true if this save context is below a given JavaScript frame. below(JavaScriptFrame * 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: AssertNoContextChange()434 AssertNoContextChange() : 435 context_(Top::context()) { 436 } 437 ~AssertNoContextChange()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