blob: aa7788e3b21ba7ad9e3114aa117bd33582bc0531 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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#include "v8.h"
29
30#include "api.h"
31#include "bootstrapper.h"
32#include "debug.h"
33#include "execution.h"
34#include "string-stream.h"
35#include "platform.h"
36
37namespace v8 {
38namespace internal {
39
40ThreadLocalTop Top::thread_local_;
41Mutex* Top::break_access_ = OS::CreateMutex();
42
43NoAllocationStringAllocator* preallocated_message_space = NULL;
44
45Address top_addresses[] = {
46#define C(name) reinterpret_cast<Address>(Top::name()),
47 TOP_ADDRESS_LIST(C)
48 TOP_ADDRESS_LIST_PROF(C)
49#undef C
50 NULL
51};
52
53Address Top::get_address_from_id(Top::AddressId id) {
54 return top_addresses[id];
55}
56
57char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
58 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
59 Iterate(v, thread);
60 return thread_storage + sizeof(ThreadLocalTop);
61}
62
63
64void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
65 v->VisitPointer(&(thread->pending_exception_));
66 v->VisitPointer(&(thread->pending_message_obj_));
67 v->VisitPointer(
68 bit_cast<Object**, Script**>(&(thread->pending_message_script_)));
69 v->VisitPointer(bit_cast<Object**, Context**>(&(thread->context_)));
70 v->VisitPointer(&(thread->scheduled_exception_));
71
72 for (v8::TryCatch* block = thread->try_catch_handler_;
73 block != NULL;
74 block = block->next_) {
75 v->VisitPointer(bit_cast<Object**, void**>(&(block->exception_)));
76 v->VisitPointer(bit_cast<Object**, void**>(&(block->message_)));
77 }
78
79 // Iterate over pointers on native execution stack.
80 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
81 it.frame()->Iterate(v);
82 }
83}
84
85
86void Top::Iterate(ObjectVisitor* v) {
87 ThreadLocalTop* current_t = &thread_local_;
88 Iterate(v, current_t);
89}
90
91
92void Top::InitializeThreadLocal() {
93 thread_local_.c_entry_fp_ = 0;
94 thread_local_.handler_ = 0;
95#ifdef ENABLE_LOGGING_AND_PROFILING
96 thread_local_.js_entry_sp_ = 0;
97#endif
98 thread_local_.stack_is_cooked_ = false;
99 thread_local_.try_catch_handler_ = NULL;
100 thread_local_.context_ = NULL;
101 int id = ThreadManager::CurrentId();
102 thread_local_.thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
103 thread_local_.external_caught_exception_ = false;
104 thread_local_.failed_access_check_callback_ = NULL;
105 clear_pending_exception();
106 clear_pending_message();
107 clear_scheduled_exception();
108 thread_local_.save_context_ = NULL;
109 thread_local_.catcher_ = NULL;
110}
111
112
113// Create a dummy thread that will wait forever on a semaphore. The only
114// purpose for this thread is to have some stack area to save essential data
115// into for use by a stacks only core dump (aka minidump).
116class PreallocatedMemoryThread: public Thread {
117 public:
118 PreallocatedMemoryThread() : keep_running_(true) {
119 wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
120 data_ready_semaphore_ = OS::CreateSemaphore(0);
121 }
122
123 // When the thread starts running it will allocate a fixed number of bytes
124 // on the stack and publish the location of this memory for others to use.
125 void Run() {
126 EmbeddedVector<char, 15 * 1024> local_buffer;
127
128 // Initialize the buffer with a known good value.
129 OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
130 local_buffer.length());
131
132 // Publish the local buffer and signal its availability.
133 data_ = local_buffer.start();
134 length_ = local_buffer.length();
135 data_ready_semaphore_->Signal();
136
137 while (keep_running_) {
138 // This thread will wait here until the end of time.
139 wait_for_ever_semaphore_->Wait();
140 }
141
142 // Make sure we access the buffer after the wait to remove all possibility
143 // of it being optimized away.
144 OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
145 local_buffer.length());
146 }
147
148 static char* data() {
149 if (data_ready_semaphore_ != NULL) {
150 // Initial access is guarded until the data has been published.
151 data_ready_semaphore_->Wait();
152 delete data_ready_semaphore_;
153 data_ready_semaphore_ = NULL;
154 }
155 return data_;
156 }
157
158 static unsigned length() {
159 if (data_ready_semaphore_ != NULL) {
160 // Initial access is guarded until the data has been published.
161 data_ready_semaphore_->Wait();
162 delete data_ready_semaphore_;
163 data_ready_semaphore_ = NULL;
164 }
165 return length_;
166 }
167
168 static void StartThread() {
169 if (the_thread_ != NULL) return;
170
171 the_thread_ = new PreallocatedMemoryThread();
172 the_thread_->Start();
173 }
174
175 // Stop the PreallocatedMemoryThread and release its resources.
176 static void StopThread() {
177 if (the_thread_ == NULL) return;
178
179 the_thread_->keep_running_ = false;
180 wait_for_ever_semaphore_->Signal();
181
182 // Wait for the thread to terminate.
183 the_thread_->Join();
184
185 if (data_ready_semaphore_ != NULL) {
186 delete data_ready_semaphore_;
187 data_ready_semaphore_ = NULL;
188 }
189
190 delete wait_for_ever_semaphore_;
191 wait_for_ever_semaphore_ = NULL;
192
193 // Done with the thread entirely.
194 delete the_thread_;
195 the_thread_ = NULL;
196 }
197
198 private:
199 // Used to make sure that the thread keeps looping even for spurious wakeups.
200 bool keep_running_;
201
202 // The preallocated memory thread singleton.
203 static PreallocatedMemoryThread* the_thread_;
204 // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
205 static Semaphore* wait_for_ever_semaphore_;
206 // Semaphore to signal that the data has been initialized.
207 static Semaphore* data_ready_semaphore_;
208
209 // Location and size of the preallocated memory block.
210 static char* data_;
211 static unsigned length_;
212
213 DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
214};
215
216PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
217Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
218Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
219char* PreallocatedMemoryThread::data_ = NULL;
220unsigned PreallocatedMemoryThread::length_ = 0;
221
222static bool initialized = false;
223
224void Top::Initialize() {
225 CHECK(!initialized);
226
227 InitializeThreadLocal();
228
229 // Only preallocate on the first initialization.
230 if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
231 // Start the thread which will set aside some memory.
232 PreallocatedMemoryThread::StartThread();
233 preallocated_message_space =
234 new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
235 PreallocatedMemoryThread::length());
236 PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
237 }
238 initialized = true;
239}
240
241
242void Top::TearDown() {
243 if (initialized) {
244 // Remove the external reference to the preallocated stack memory.
245 if (preallocated_message_space != NULL) {
246 delete preallocated_message_space;
247 preallocated_message_space = NULL;
248 }
249
250 PreallocatedMemoryThread::StopThread();
251 initialized = false;
252 }
253}
254
255
256// There are cases where the C stack is separated from JS stack (ARM simulator).
257// To figure out the order of top-most JS try-catch handler and the top-most C
258// try-catch handler, the C try-catch handler keeps a reference to the top-most
259// JS try_catch handler when it was created.
260//
261// Here is a picture to explain the idea:
262// Top::thread_local_.handler_ Top::thread_local_.try_catch_handler_
263//
264// | |
265// v v
266//
267// | JS handler | | C try_catch handler |
268// | next |--+ +-------- | js_handler_ |
269// | | | next_ |--+
270// | | |
271// | JS handler |--+ <---------+ |
272// | next |
273//
274// If the top-most JS try-catch handler is not equal to
275// Top::thread_local_.try_catch_handler_.js_handler_, it means the JS handler
276// is on the top. Otherwise, it means the C try-catch handler is on the top.
277//
278void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
279 StackHandler* handler =
280 reinterpret_cast<StackHandler*>(thread_local_.handler_);
281
282 // Find the top-most try-catch handler.
283 while (handler != NULL && !handler->is_try_catch()) {
284 handler = handler->next();
285 }
286
287 that->js_handler_ = handler; // casted to void*
288 thread_local_.try_catch_handler_ = that;
289}
290
291
292void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
293 ASSERT(thread_local_.try_catch_handler_ == that);
294 thread_local_.try_catch_handler_ = that->next_;
295 thread_local_.catcher_ = NULL;
296}
297
298
299void Top::MarkCompactPrologue(bool is_compacting) {
300 MarkCompactPrologue(is_compacting, &thread_local_);
301}
302
303
304void Top::MarkCompactPrologue(bool is_compacting, char* data) {
305 MarkCompactPrologue(is_compacting, reinterpret_cast<ThreadLocalTop*>(data));
306}
307
308
309void Top::MarkCompactPrologue(bool is_compacting, ThreadLocalTop* thread) {
310 if (is_compacting) {
311 StackFrame::CookFramesForThread(thread);
312 }
313}
314
315
316void Top::MarkCompactEpilogue(bool is_compacting, char* data) {
317 MarkCompactEpilogue(is_compacting, reinterpret_cast<ThreadLocalTop*>(data));
318}
319
320
321void Top::MarkCompactEpilogue(bool is_compacting) {
322 MarkCompactEpilogue(is_compacting, &thread_local_);
323}
324
325
326void Top::MarkCompactEpilogue(bool is_compacting, ThreadLocalTop* thread) {
327 if (is_compacting) {
328 StackFrame::UncookFramesForThread(thread);
329 }
330}
331
332
333static int stack_trace_nesting_level = 0;
334static StringStream* incomplete_message = NULL;
335
336
337Handle<String> Top::StackTrace() {
338 if (stack_trace_nesting_level == 0) {
339 stack_trace_nesting_level++;
340 HeapStringAllocator allocator;
341 StringStream::ClearMentionedObjectCache();
342 StringStream accumulator(&allocator);
343 incomplete_message = &accumulator;
344 PrintStack(&accumulator);
345 Handle<String> stack_trace = accumulator.ToString();
346 incomplete_message = NULL;
347 stack_trace_nesting_level = 0;
348 return stack_trace;
349 } else if (stack_trace_nesting_level == 1) {
350 stack_trace_nesting_level++;
351 OS::PrintError(
352 "\n\nAttempt to print stack while printing stack (double fault)\n");
353 OS::PrintError(
354 "If you are lucky you may find a partial stack dump on stdout.\n\n");
355 incomplete_message->OutputToStdOut();
356 return Factory::empty_symbol();
357 } else {
358 OS::Abort();
359 // Unreachable
360 return Factory::empty_symbol();
361 }
362}
363
364
365void Top::PrintStack() {
366 if (stack_trace_nesting_level == 0) {
367 stack_trace_nesting_level++;
368
369 StringAllocator* allocator;
370 if (preallocated_message_space == NULL) {
371 allocator = new HeapStringAllocator();
372 } else {
373 allocator = preallocated_message_space;
374 }
375
376 NativeAllocationChecker allocation_checker(
377 !FLAG_preallocate_message_memory ?
378 NativeAllocationChecker::ALLOW :
379 NativeAllocationChecker::DISALLOW);
380
381 StringStream::ClearMentionedObjectCache();
382 StringStream accumulator(allocator);
383 incomplete_message = &accumulator;
384 PrintStack(&accumulator);
385 accumulator.OutputToStdOut();
386 accumulator.Log();
387 incomplete_message = NULL;
388 stack_trace_nesting_level = 0;
389 if (preallocated_message_space == NULL) {
390 // Remove the HeapStringAllocator created above.
391 delete allocator;
392 }
393 } else if (stack_trace_nesting_level == 1) {
394 stack_trace_nesting_level++;
395 OS::PrintError(
396 "\n\nAttempt to print stack while printing stack (double fault)\n");
397 OS::PrintError(
398 "If you are lucky you may find a partial stack dump on stdout.\n\n");
399 incomplete_message->OutputToStdOut();
400 }
401}
402
403
404static void PrintFrames(StringStream* accumulator,
405 StackFrame::PrintMode mode) {
406 StackFrameIterator it;
407 for (int i = 0; !it.done(); it.Advance()) {
408 it.frame()->Print(accumulator, mode, i++);
409 }
410}
411
412
413void Top::PrintStack(StringStream* accumulator) {
414 // The MentionedObjectCache is not GC-proof at the moment.
415 AssertNoAllocation nogc;
416 ASSERT(StringStream::IsMentionedObjectCacheClear());
417
418 // Avoid printing anything if there are no frames.
419 if (c_entry_fp(GetCurrentThread()) == 0) return;
420
421 accumulator->Add(
422 "\n==== Stack trace ============================================\n\n");
423 PrintFrames(accumulator, StackFrame::OVERVIEW);
424
425 accumulator->Add(
426 "\n==== Details ================================================\n\n");
427 PrintFrames(accumulator, StackFrame::DETAILS);
428
429 accumulator->PrintMentionedObjectCache();
430 accumulator->Add("=====================\n\n");
431}
432
433
434void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
435 ASSERT(thread_local_.failed_access_check_callback_ == NULL);
436 thread_local_.failed_access_check_callback_ = callback;
437}
438
439
440void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
441 if (!thread_local_.failed_access_check_callback_) return;
442
443 ASSERT(receiver->IsAccessCheckNeeded());
444 ASSERT(Top::context());
445 // The callers of this method are not expecting a GC.
446 AssertNoAllocation no_gc;
447
448 // Get the data object from access check info.
449 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
450 Object* info = constructor->shared()->function_data();
451 if (info == Heap::undefined_value()) return;
452
453 Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
454 if (data_obj == Heap::undefined_value()) return;
455
456 HandleScope scope;
457 Handle<JSObject> receiver_handle(receiver);
458 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
459 thread_local_.failed_access_check_callback_(
460 v8::Utils::ToLocal(receiver_handle),
461 type,
462 v8::Utils::ToLocal(data));
463}
464
465
466enum MayAccessDecision {
467 YES, NO, UNKNOWN
468};
469
470
471static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
472 v8::AccessType type) {
473 // During bootstrapping, callback functions are not enabled yet.
474 if (Bootstrapper::IsActive()) return YES;
475
476 if (receiver->IsJSGlobalProxy()) {
477 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
478 if (!receiver_context->IsContext()) return NO;
479
480 // Get the global context of current top context.
481 // avoid using Top::global_context() because it uses Handle.
482 Context* global_context = Top::context()->global()->global_context();
483 if (receiver_context == global_context) return YES;
484
485 if (Context::cast(receiver_context)->security_token() ==
486 global_context->security_token())
487 return YES;
488 }
489
490 return UNKNOWN;
491}
492
493
494bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
495 ASSERT(receiver->IsAccessCheckNeeded());
496 // Check for compatibility between the security tokens in the
497 // current lexical context and the accessed object.
498 ASSERT(Top::context());
499 // The callers of this method are not expecting a GC.
500 AssertNoAllocation no_gc;
501
502 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
503 if (decision != UNKNOWN) return decision == YES;
504
505 // Get named access check callback
506 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
507 Object* info = constructor->shared()->function_data();
508 if (info == Heap::undefined_value()) return false;
509
510 Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
511 if (data_obj == Heap::undefined_value()) return false;
512
513 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
514 v8::NamedSecurityCallback callback =
515 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
516
517 if (!callback) return false;
518
519 HandleScope scope;
520 Handle<JSObject> receiver_handle(receiver);
521 Handle<Object> key_handle(key);
522 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
523 LOG(ApiNamedSecurityCheck(key));
524 bool result = false;
525 {
526 // Leaving JavaScript.
527 VMState state(EXTERNAL);
528 result = callback(v8::Utils::ToLocal(receiver_handle),
529 v8::Utils::ToLocal(key_handle),
530 type,
531 v8::Utils::ToLocal(data));
532 }
533 return result;
534}
535
536
537bool Top::MayIndexedAccess(JSObject* receiver,
538 uint32_t index,
539 v8::AccessType type) {
540 ASSERT(receiver->IsAccessCheckNeeded());
541 // Check for compatibility between the security tokens in the
542 // current lexical context and the accessed object.
543 ASSERT(Top::context());
544 // The callers of this method are not expecting a GC.
545 AssertNoAllocation no_gc;
546
547 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
548 if (decision != UNKNOWN) return decision == YES;
549
550 // Get indexed access check callback
551 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
552 Object* info = constructor->shared()->function_data();
553 if (info == Heap::undefined_value()) return false;
554
555 Object* data_obj = FunctionTemplateInfo::cast(info)->access_check_info();
556 if (data_obj == Heap::undefined_value()) return false;
557
558 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
559 v8::IndexedSecurityCallback callback =
560 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
561
562 if (!callback) return false;
563
564 HandleScope scope;
565 Handle<JSObject> receiver_handle(receiver);
566 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
567 LOG(ApiIndexedSecurityCheck(index));
568 bool result = false;
569 {
570 // Leaving JavaScript.
571 VMState state(EXTERNAL);
572 result = callback(v8::Utils::ToLocal(receiver_handle),
573 index,
574 type,
575 v8::Utils::ToLocal(data));
576 }
577 return result;
578}
579
580
581const char* Top::kStackOverflowMessage =
582 "Uncaught RangeError: Maximum call stack size exceeded";
583
584
585Failure* Top::StackOverflow() {
586 HandleScope scope;
587 Handle<String> key = Factory::stack_overflow_symbol();
588 Handle<JSObject> boilerplate =
589 Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
590 Handle<Object> exception = Copy(boilerplate);
591 // TODO(1240995): To avoid having to call JavaScript code to compute
592 // the message for stack overflow exceptions which is very likely to
593 // double fault with another stack overflow exception, we use a
594 // precomputed message. This is somewhat problematic in that it
595 // doesn't use ReportUncaughtException to determine the location
596 // from where the exception occurred. It should probably be
597 // reworked.
598 DoThrow(*exception, NULL, kStackOverflowMessage);
599 return Failure::Exception();
600}
601
602
603Failure* Top::TerminateExecution() {
604 DoThrow(Heap::termination_exception(), NULL, NULL);
605 return Failure::Exception();
606}
607
608
609Failure* Top::Throw(Object* exception, MessageLocation* location) {
610 DoThrow(exception, location, NULL);
611 return Failure::Exception();
612}
613
614
615Failure* Top::ReThrow(Object* exception, MessageLocation* location) {
616 // Set the exception being re-thrown.
617 set_pending_exception(exception);
618 return Failure::Exception();
619}
620
621
622Failure* Top::ThrowIllegalOperation() {
623 return Throw(Heap::illegal_access_symbol());
624}
625
626
627void Top::ScheduleThrow(Object* exception) {
628 // When scheduling a throw we first throw the exception to get the
629 // error reporting if it is uncaught before rescheduling it.
630 Throw(exception);
631 thread_local_.scheduled_exception_ = pending_exception();
632 thread_local_.external_caught_exception_ = false;
633 clear_pending_exception();
634}
635
636
637Object* Top::PromoteScheduledException() {
638 Object* thrown = scheduled_exception();
639 clear_scheduled_exception();
640 // Re-throw the exception to avoid getting repeated error reporting.
641 return ReThrow(thrown);
642}
643
644
645void Top::PrintCurrentStackTrace(FILE* out) {
646 StackTraceFrameIterator it;
647 while (!it.done()) {
648 HandleScope scope;
649 // Find code position if recorded in relocation info.
650 JavaScriptFrame* frame = it.frame();
651 int pos = frame->code()->SourcePosition(frame->pc());
652 Handle<Object> pos_obj(Smi::FromInt(pos));
653 // Fetch function and receiver.
654 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
655 Handle<Object> recv(frame->receiver());
656 // Advance to the next JavaScript frame and determine if the
657 // current frame is the top-level frame.
658 it.Advance();
659 Handle<Object> is_top_level = it.done()
660 ? Factory::true_value()
661 : Factory::false_value();
662 // Generate and print stack trace line.
663 Handle<String> line =
664 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
665 if (line->length() > 0) {
666 line->PrintOn(out);
667 fprintf(out, "\n");
668 }
669 }
670}
671
672
673void Top::ComputeLocation(MessageLocation* target) {
674 *target = MessageLocation(empty_script(), -1, -1);
675 StackTraceFrameIterator it;
676 if (!it.done()) {
677 JavaScriptFrame* frame = it.frame();
678 JSFunction* fun = JSFunction::cast(frame->function());
679 Object* script = fun->shared()->script();
680 if (script->IsScript() &&
681 !(Script::cast(script)->source()->IsUndefined())) {
682 int pos = frame->code()->SourcePosition(frame->pc());
683 // Compute the location from the function and the reloc info.
684 Handle<Script> casted_script(Script::cast(script));
685 *target = MessageLocation(casted_script, pos, pos + 1);
686 }
687 }
688}
689
690
691void Top::ReportUncaughtException(Handle<Object> exception,
692 MessageLocation* location,
693 Handle<String> stack_trace) {
694 Handle<Object> message;
695 if (!Bootstrapper::IsActive()) {
696 // It's not safe to try to make message objects while the bootstrapper
697 // is active since the infrastructure may not have been properly
698 // initialized.
699 message =
700 MessageHandler::MakeMessageObject("uncaught_exception",
701 location,
702 HandleVector<Object>(&exception, 1),
703 stack_trace);
704 }
705 // Report the uncaught exception.
706 MessageHandler::ReportMessage(location, message);
707}
708
709
710bool Top::ShouldReturnException(bool* is_caught_externally,
711 bool catchable_by_javascript) {
712 // Find the top-most try-catch handler.
713 StackHandler* handler =
714 StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
715 while (handler != NULL && !handler->is_try_catch()) {
716 handler = handler->next();
717 }
718
719 // Get the address of the external handler so we can compare the address to
720 // determine which one is closer to the top of the stack.
721 v8::TryCatch* try_catch = thread_local_.try_catch_handler_;
722
723 // The exception has been externally caught if and only if there is
724 // an external handler which is on top of the top-most try-catch
725 // handler.
726 //
727 // See comments in RegisterTryCatchHandler for details.
728 *is_caught_externally = try_catch != NULL &&
729 (handler == NULL || handler == try_catch->js_handler_ ||
730 !catchable_by_javascript);
731
732 if (*is_caught_externally) {
733 // Only report the exception if the external handler is verbose.
734 return thread_local_.try_catch_handler_->is_verbose_;
735 } else {
736 // Report the exception if it isn't caught by JavaScript code.
737 return handler == NULL;
738 }
739}
740
741
742void Top::DoThrow(Object* exception,
743 MessageLocation* location,
744 const char* message) {
745 ASSERT(!has_pending_exception());
746
747 HandleScope scope;
748 Handle<Object> exception_handle(exception);
749
750 // Determine reporting and whether the exception is caught externally.
751 bool is_caught_externally = false;
752 bool is_out_of_memory = exception == Failure::OutOfMemoryException();
753 bool is_termination_exception = exception == Heap::termination_exception();
754 bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory;
755 bool should_return_exception =
756 ShouldReturnException(&is_caught_externally, catchable_by_javascript);
757 bool report_exception = catchable_by_javascript && should_return_exception;
758
759#ifdef ENABLE_DEBUGGER_SUPPORT
760 // Notify debugger of exception.
761 if (catchable_by_javascript) {
762 Debugger::OnException(exception_handle, report_exception);
763 }
764#endif
765
766 // Generate the message.
767 Handle<Object> message_obj;
768 MessageLocation potential_computed_location;
769 bool try_catch_needs_message =
770 is_caught_externally &&
771 thread_local_.try_catch_handler_->capture_message_;
772 if (report_exception || try_catch_needs_message) {
773 if (location == NULL) {
774 // If no location was specified we use a computed one instead
775 ComputeLocation(&potential_computed_location);
776 location = &potential_computed_location;
777 }
778 if (!Bootstrapper::IsActive()) {
779 // It's not safe to try to make message objects or collect stack
780 // traces while the bootstrapper is active since the infrastructure
781 // may not have been properly initialized.
782 Handle<String> stack_trace;
783 if (FLAG_trace_exception) stack_trace = StackTrace();
784 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
785 location, HandleVector<Object>(&exception_handle, 1), stack_trace);
786 }
787 }
788
789 // Save the message for reporting if the the exception remains uncaught.
790 thread_local_.has_pending_message_ = report_exception;
791 thread_local_.pending_message_ = message;
792 if (!message_obj.is_null()) {
793 thread_local_.pending_message_obj_ = *message_obj;
794 if (location != NULL) {
795 thread_local_.pending_message_script_ = *location->script();
796 thread_local_.pending_message_start_pos_ = location->start_pos();
797 thread_local_.pending_message_end_pos_ = location->end_pos();
798 }
799 }
800
801 if (is_caught_externally) {
802 thread_local_.catcher_ = thread_local_.try_catch_handler_;
803 }
804
805 // NOTE: Notifying the debugger or generating the message
806 // may have caused new exceptions. For now, we just ignore
807 // that and set the pending exception to the original one.
808 set_pending_exception(*exception_handle);
809}
810
811
812void Top::ReportPendingMessages() {
813 ASSERT(has_pending_exception());
814 setup_external_caught();
815 // If the pending exception is OutOfMemoryException set out_of_memory in
816 // the global context. Note: We have to mark the global context here
817 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
818 // set it.
819 bool external_caught = thread_local_.external_caught_exception_;
820 HandleScope scope;
821 if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
822 context()->mark_out_of_memory();
823 } else if (thread_local_.pending_exception_ ==
824 Heap::termination_exception()) {
825 if (external_caught) {
826 thread_local_.try_catch_handler_->can_continue_ = false;
827 thread_local_.try_catch_handler_->exception_ = Heap::null_value();
828 }
829 } else {
830 Handle<Object> exception(pending_exception());
831 thread_local_.external_caught_exception_ = false;
832 if (external_caught) {
833 thread_local_.try_catch_handler_->can_continue_ = true;
834 thread_local_.try_catch_handler_->exception_ =
835 thread_local_.pending_exception_;
836 if (!thread_local_.pending_message_obj_->IsTheHole()) {
837 try_catch_handler()->message_ = thread_local_.pending_message_obj_;
838 }
839 }
840 if (thread_local_.has_pending_message_) {
841 thread_local_.has_pending_message_ = false;
842 if (thread_local_.pending_message_ != NULL) {
843 MessageHandler::ReportMessage(thread_local_.pending_message_);
844 } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
845 Handle<Object> message_obj(thread_local_.pending_message_obj_);
846 if (thread_local_.pending_message_script_ != NULL) {
847 Handle<Script> script(thread_local_.pending_message_script_);
848 int start_pos = thread_local_.pending_message_start_pos_;
849 int end_pos = thread_local_.pending_message_end_pos_;
850 MessageLocation location(script, start_pos, end_pos);
851 MessageHandler::ReportMessage(&location, message_obj);
852 } else {
853 MessageHandler::ReportMessage(NULL, message_obj);
854 }
855 }
856 }
857 thread_local_.external_caught_exception_ = external_caught;
858 set_pending_exception(*exception);
859 }
860 clear_pending_message();
861}
862
863
864void Top::TraceException(bool flag) {
865 FLAG_trace_exception = flag;
866}
867
868
869bool Top::OptionalRescheduleException(bool is_bottom_call) {
870 // Allways reschedule out of memory exceptions.
871 if (!is_out_of_memory()) {
872 bool is_termination_exception =
873 pending_exception() == Heap::termination_exception();
874
875 // Do not reschedule the exception if this is the bottom call.
876 bool clear_exception = is_bottom_call;
877
878 if (is_termination_exception) {
879 if (is_bottom_call) {
880 thread_local_.external_caught_exception_ = false;
881 clear_pending_exception();
882 return false;
883 }
884 } else if (thread_local_.external_caught_exception_) {
885 // If the exception is externally caught, clear it if there are no
886 // JavaScript frames on the way to the C++ frame that has the
887 // external handler.
888 ASSERT(thread_local_.try_catch_handler_ != NULL);
889 Address external_handler_address =
890 reinterpret_cast<Address>(thread_local_.try_catch_handler_);
891 JavaScriptFrameIterator it;
892 if (it.done() || (it.frame()->sp() > external_handler_address)) {
893 clear_exception = true;
894 }
895 }
896
897 // Clear the exception if needed.
898 if (clear_exception) {
899 thread_local_.external_caught_exception_ = false;
900 clear_pending_exception();
901 return false;
902 }
903 }
904
905 // Reschedule the exception.
906 thread_local_.scheduled_exception_ = pending_exception();
907 clear_pending_exception();
908 return true;
909}
910
911
912bool Top::is_out_of_memory() {
913 if (has_pending_exception()) {
914 Object* e = pending_exception();
915 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
916 return true;
917 }
918 }
919 if (has_scheduled_exception()) {
920 Object* e = scheduled_exception();
921 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
922 return true;
923 }
924 }
925 return false;
926}
927
928
929Handle<Context> Top::global_context() {
930 GlobalObject* global = thread_local_.context_->global();
931 return Handle<Context>(global->global_context());
932}
933
934
935Handle<Context> Top::GetCallingGlobalContext() {
936 JavaScriptFrameIterator it;
937 if (it.done()) return Handle<Context>::null();
938 JavaScriptFrame* frame = it.frame();
939 Context* context = Context::cast(frame->context());
940 return Handle<Context>(context->global_context());
941}
942
943
944Object* Top::LookupSpecialFunction(JSObject* receiver,
945 JSObject* prototype,
946 JSFunction* function) {
947 if (receiver->IsJSArray()) {
948 FixedArray* table = context()->global_context()->special_function_table();
949 for (int index = 0; index < table->length(); index +=3) {
950 if ((prototype == table->get(index)) &&
951 (function == table->get(index+1))) {
952 return table->get(index+2);
953 }
954 }
955 }
956 return Heap::undefined_value();
957}
958
959
960char* Top::ArchiveThread(char* to) {
961 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
962 InitializeThreadLocal();
963 return to + sizeof(thread_local_);
964}
965
966
967char* Top::RestoreThread(char* from) {
968 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
969 return from + sizeof(thread_local_);
970}
971
972
973ExecutionAccess::ExecutionAccess() {
974 Top::break_access_->Lock();
975}
976
977
978ExecutionAccess::~ExecutionAccess() {
979 Top::break_access_->Unlock();
980}
981
982
983} } // namespace v8::internal