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