• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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