• 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   // 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