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 // The context where the current execution method is created and for variable 47 // lookups. 48 Context* context_; 49 int thread_id_; 50 Object* pending_exception_; 51 bool has_pending_message_; 52 const char* pending_message_; 53 Object* pending_message_obj_; 54 Script* pending_message_script_; 55 int pending_message_start_pos_; 56 int pending_message_end_pos_; 57 // Use a separate value for scheduled exceptions to preserve the 58 // invariants that hold about pending_exception. We may want to 59 // unify them later. 60 Object* scheduled_exception_; 61 bool external_caught_exception_; 62 v8::TryCatch* try_catch_handler_; 63 SaveContext* save_context_; 64 v8::TryCatch* catcher_; 65 66 // Stack. 67 Address c_entry_fp_; // the frame pointer of the top c entry frame 68 Address handler_; // try-blocks are chained through the stack 69 #ifdef ENABLE_LOGGING_AND_PROFILING 70 Address js_entry_sp_; // the stack pointer of the bottom js entry frame 71 #endif 72 bool stack_is_cooked_; stack_is_cooked()73 inline bool stack_is_cooked() { return stack_is_cooked_; } set_stack_is_cooked(bool value)74 inline void set_stack_is_cooked(bool value) { stack_is_cooked_ = value; } 75 76 // Generated code scratch locations. 77 int32_t formal_count_; 78 79 // Call back function to report unsafe JS accesses. 80 v8::FailedAccessCheckCallback failed_access_check_callback_; 81 }; 82 83 #define TOP_ADDRESS_LIST(C) \ 84 C(handler_address) \ 85 C(c_entry_fp_address) \ 86 C(context_address) \ 87 C(pending_exception_address) \ 88 C(external_caught_exception_address) 89 90 #ifdef ENABLE_LOGGING_AND_PROFILING 91 #define TOP_ADDRESS_LIST_PROF(C) \ 92 C(js_entry_sp_address) 93 #else 94 #define TOP_ADDRESS_LIST_PROF(C) 95 #endif 96 97 98 class Top { 99 public: 100 enum AddressId { 101 #define C(name) k_##name, 102 TOP_ADDRESS_LIST(C) 103 TOP_ADDRESS_LIST_PROF(C) 104 #undef C 105 k_top_address_count 106 }; 107 108 static Address get_address_from_id(AddressId id); 109 110 // Access to top context (where the current function object was created). context()111 static Context* context() { return thread_local_.context_; } set_context(Context * context)112 static void set_context(Context* context) { 113 thread_local_.context_ = context; 114 } context_address()115 static Context** context_address() { return &thread_local_.context_; } 116 save_context()117 static SaveContext* save_context() {return thread_local_.save_context_; } set_save_context(SaveContext * save)118 static void set_save_context(SaveContext* save) { 119 thread_local_.save_context_ = save; 120 } 121 122 // Access to current thread id. thread_id()123 static int thread_id() { return thread_local_.thread_id_; } set_thread_id(int id)124 static void set_thread_id(int id) { thread_local_.thread_id_ = id; } 125 126 // Interface to pending exception. pending_exception()127 static Object* pending_exception() { 128 ASSERT(has_pending_exception()); 129 return thread_local_.pending_exception_; 130 } external_caught_exception()131 static bool external_caught_exception() { 132 return thread_local_.external_caught_exception_; 133 } set_pending_exception(Object * exception)134 static void set_pending_exception(Object* exception) { 135 thread_local_.pending_exception_ = exception; 136 } clear_pending_exception()137 static void clear_pending_exception() { 138 thread_local_.pending_exception_ = Heap::the_hole_value(); 139 } 140 pending_exception_address()141 static Object** pending_exception_address() { 142 return &thread_local_.pending_exception_; 143 } has_pending_exception()144 static bool has_pending_exception() { 145 return !thread_local_.pending_exception_->IsTheHole(); 146 } clear_pending_message()147 static void clear_pending_message() { 148 thread_local_.has_pending_message_ = false; 149 thread_local_.pending_message_ = NULL; 150 thread_local_.pending_message_obj_ = Heap::the_hole_value(); 151 thread_local_.pending_message_script_ = NULL; 152 } try_catch_handler()153 static v8::TryCatch* try_catch_handler() { 154 return thread_local_.try_catch_handler_; 155 } 156 // This method is called by the api after operations that may throw 157 // exceptions. If an exception was thrown and not handled by an external 158 // handler the exception is scheduled to be rethrown when we return to running 159 // JavaScript code. If an exception is scheduled true is returned. 160 static bool OptionalRescheduleException(bool is_bottom_call); 161 162 external_caught_exception_address()163 static bool* external_caught_exception_address() { 164 return &thread_local_.external_caught_exception_; 165 } 166 scheduled_exception()167 static Object* scheduled_exception() { 168 ASSERT(has_scheduled_exception()); 169 return thread_local_.scheduled_exception_; 170 } has_scheduled_exception()171 static bool has_scheduled_exception() { 172 return !thread_local_.scheduled_exception_->IsTheHole(); 173 } clear_scheduled_exception()174 static void clear_scheduled_exception() { 175 thread_local_.scheduled_exception_ = Heap::the_hole_value(); 176 } 177 setup_external_caught()178 static void setup_external_caught() { 179 thread_local_.external_caught_exception_ = 180 has_pending_exception() && 181 (thread_local_.catcher_ != NULL) && 182 (thread_local_.try_catch_handler_ == thread_local_.catcher_); 183 } 184 185 // Tells whether the current context has experienced an out of memory 186 // exception. 187 static bool is_out_of_memory(); 188 189 // JS execution stack (see frames.h). c_entry_fp(ThreadLocalTop * thread)190 static Address c_entry_fp(ThreadLocalTop* thread) { 191 return thread->c_entry_fp_; 192 } handler(ThreadLocalTop * thread)193 static Address handler(ThreadLocalTop* thread) { return thread->handler_; } 194 c_entry_fp_address()195 static inline Address* c_entry_fp_address() { 196 return &thread_local_.c_entry_fp_; 197 } handler_address()198 static inline Address* handler_address() { return &thread_local_.handler_; } 199 200 #ifdef ENABLE_LOGGING_AND_PROFILING 201 // Bottom JS entry (see StackTracer::Trace in log.cc). js_entry_sp(ThreadLocalTop * thread)202 static Address js_entry_sp(ThreadLocalTop* thread) { 203 return thread->js_entry_sp_; 204 } js_entry_sp_address()205 static inline Address* js_entry_sp_address() { 206 return &thread_local_.js_entry_sp_; 207 } 208 #endif 209 210 // Generated code scratch locations. formal_count_address()211 static void* formal_count_address() { return &thread_local_.formal_count_; } 212 213 static void MarkCompactPrologue(bool is_compacting); 214 static void MarkCompactEpilogue(bool is_compacting); 215 static void MarkCompactPrologue(bool is_compacting, 216 char* archived_thread_data); 217 static void MarkCompactEpilogue(bool is_compacting, 218 char* archived_thread_data); 219 static void PrintCurrentStackTrace(FILE* out); 220 static void PrintStackTrace(FILE* out, char* thread_data); 221 static void PrintStack(StringStream* accumulator); 222 static void PrintStack(); 223 static Handle<String> StackTrace(); 224 225 // Returns if the top context may access the given global object. If 226 // the result is false, the pending exception is guaranteed to be 227 // set. 228 static bool MayNamedAccess(JSObject* receiver, 229 Object* key, 230 v8::AccessType type); 231 static bool MayIndexedAccess(JSObject* receiver, 232 uint32_t index, 233 v8::AccessType type); 234 235 static void SetFailedAccessCheckCallback( 236 v8::FailedAccessCheckCallback callback); 237 static void ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type); 238 239 // Exception throwing support. The caller should use the result 240 // of Throw() as its return value. 241 static Failure* Throw(Object* exception, MessageLocation* location = NULL); 242 // Re-throw an exception. This involves no error reporting since 243 // error reporting was handled when the exception was thrown 244 // originally. 245 static Failure* ReThrow(Object* exception, MessageLocation* location = NULL); 246 static void ScheduleThrow(Object* exception); 247 static void ReportPendingMessages(); 248 static Failure* ThrowIllegalOperation(); 249 250 // Promote a scheduled exception to pending. Asserts has_scheduled_exception. 251 static Object* PromoteScheduledException(); 252 static void DoThrow(Object* exception, 253 MessageLocation* location, 254 const char* message); 255 static bool ShouldReturnException(bool* is_caught_externally, 256 bool catchable_by_javascript); 257 static void ReportUncaughtException(Handle<Object> exception, 258 MessageLocation* location, 259 Handle<String> stack_trace); 260 261 // Attempts to compute the current source location, storing the 262 // result in the target out parameter. 263 static void ComputeLocation(MessageLocation* target); 264 265 // Override command line flag. 266 static void TraceException(bool flag); 267 268 // Out of resource exception helpers. 269 static Failure* StackOverflow(); 270 static Failure* TerminateExecution(); 271 272 // Administration 273 static void Initialize(); 274 static void TearDown(); 275 static void Iterate(ObjectVisitor* v); 276 static void Iterate(ObjectVisitor* v, ThreadLocalTop* t); 277 static char* Iterate(ObjectVisitor* v, char* t); 278 279 // Returns the global object of the current context. It could be 280 // a builtin object, or a js global object. global()281 static Handle<GlobalObject> global() { 282 return Handle<GlobalObject>(context()->global()); 283 } 284 285 // Returns the global proxy object of the current context. global_proxy()286 static Object* global_proxy() { 287 return context()->global_proxy(); 288 } 289 290 // Returns the current global context. 291 static Handle<Context> global_context(); 292 293 // Returns the global context of the calling JavaScript code. That 294 // is, the global context of the top-most JavaScript frame. 295 static Handle<Context> GetCallingGlobalContext(); 296 builtins()297 static Handle<JSBuiltinsObject> builtins() { 298 return Handle<JSBuiltinsObject>(thread_local_.context_->builtins()); 299 } 300 301 static Object* LookupSpecialFunction(JSObject* receiver, 302 JSObject* prototype, 303 JSFunction* value); 304 305 static void RegisterTryCatchHandler(v8::TryCatch* that); 306 static void UnregisterTryCatchHandler(v8::TryCatch* that); 307 308 #define TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR(index, type, name) \ 309 static Handle<type> name() { \ 310 return Handle<type>(context()->global_context()->name()); \ 311 } GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR)312 GLOBAL_CONTEXT_FIELDS(TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR) 313 #undef TOP_GLOBAL_CONTEXT_FIELD_ACCESSOR 314 315 static inline ThreadLocalTop* GetCurrentThread() { return &thread_local_; } ArchiveSpacePerThread()316 static int ArchiveSpacePerThread() { return sizeof(ThreadLocalTop); } 317 static char* ArchiveThread(char* to); 318 static char* RestoreThread(char* from); 319 320 static const char* kStackOverflowMessage; 321 322 private: 323 // The context that initiated this JS execution. 324 static ThreadLocalTop thread_local_; 325 static void InitializeThreadLocal(); 326 static void PrintStackTrace(FILE* out, ThreadLocalTop* thread); 327 static void MarkCompactPrologue(bool is_compacting, 328 ThreadLocalTop* archived_thread_data); 329 static void MarkCompactEpilogue(bool is_compacting, 330 ThreadLocalTop* archived_thread_data); 331 332 // Debug. 333 // Mutex for serializing access to break control structures. 334 static Mutex* break_access_; 335 336 friend class SaveContext; 337 friend class AssertNoContextChange; 338 friend class ExecutionAccess; 339 340 static void FillCache(); 341 }; 342 343 344 // If the GCC version is 4.1.x or 4.2.x an additional field is added to the 345 // class as a work around for a bug in the generated code found with these 346 // versions of GCC. See V8 issue 122 for details. 347 class SaveContext BASE_EMBEDDED { 348 public: SaveContext()349 SaveContext() 350 : context_(Top::context()), 351 #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 352 dummy_(Top::context()), 353 #endif 354 prev_(Top::save_context()) { 355 Top::set_save_context(this); 356 357 // If there is no JS frame under the current C frame, use the value 0. 358 JavaScriptFrameIterator it; 359 js_sp_ = it.done() ? 0 : it.frame()->sp(); 360 } 361 ~SaveContext()362 ~SaveContext() { 363 Top::set_context(*context_); 364 Top::set_save_context(prev_); 365 } 366 context()367 Handle<Context> context() { return context_; } prev()368 SaveContext* prev() { return prev_; } 369 370 // Returns true if this save context is below a given JavaScript frame. below(JavaScriptFrame * frame)371 bool below(JavaScriptFrame* frame) { 372 return (js_sp_ == 0) || (frame->sp() < js_sp_); 373 } 374 375 private: 376 Handle<Context> context_; 377 #if __GNUC_VERSION__ >= 40100 && __GNUC_VERSION__ < 40300 378 Handle<Context> dummy_; 379 #endif 380 SaveContext* prev_; 381 Address js_sp_; // The top JS frame's sp when saving context. 382 }; 383 384 385 class AssertNoContextChange BASE_EMBEDDED { 386 #ifdef DEBUG 387 public: AssertNoContextChange()388 AssertNoContextChange() : 389 context_(Top::context()) { 390 } 391 ~AssertNoContextChange()392 ~AssertNoContextChange() { 393 ASSERT(Top::context() == *context_); 394 } 395 396 private: 397 HandleScope scope_; 398 Handle<Context> context_; 399 #else 400 public: 401 AssertNoContextChange() { } 402 #endif 403 }; 404 405 406 class ExecutionAccess BASE_EMBEDDED { 407 public: 408 ExecutionAccess(); 409 ~ExecutionAccess(); 410 }; 411 412 } } // namespace v8::internal 413 414 #endif // V8_TOP_H_ 415