blob: 2887b7664fd5a10744c131ec80766bcba3201dfb [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"
Steve Block6ded16b2010-05-10 14:33:55 +010034#include "messages.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "platform.h"
Steve Blockd0582a62009-12-15 09:54:21 +000036#include "simulator.h"
37#include "string-stream.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000038
39namespace v8 {
40namespace internal {
41
42ThreadLocalTop Top::thread_local_;
43Mutex* Top::break_access_ = OS::CreateMutex();
44
45NoAllocationStringAllocator* preallocated_message_space = NULL;
46
Ben Murdoch3bec4d22010-07-22 14:51:16 +010047bool capture_stack_trace_for_uncaught_exceptions = false;
48int stack_trace_for_uncaught_exceptions_frame_limit = 0;
49StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options =
50 StackTrace::kOverview;
51
Steve Blocka7e24c12009-10-30 11:49:00 +000052Address top_addresses[] = {
53#define C(name) reinterpret_cast<Address>(Top::name()),
54 TOP_ADDRESS_LIST(C)
55 TOP_ADDRESS_LIST_PROF(C)
56#undef C
57 NULL
58};
59
Steve Blockd0582a62009-12-15 09:54:21 +000060
61v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
62 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
63}
64
65
66void ThreadLocalTop::Initialize() {
67 c_entry_fp_ = 0;
68 handler_ = 0;
69#ifdef ENABLE_LOGGING_AND_PROFILING
70 js_entry_sp_ = 0;
71#endif
72 stack_is_cooked_ = false;
73 try_catch_handler_address_ = NULL;
74 context_ = NULL;
75 int id = ThreadManager::CurrentId();
76 thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
77 external_caught_exception_ = false;
78 failed_access_check_callback_ = NULL;
79 save_context_ = NULL;
80 catcher_ = NULL;
81}
82
83
Steve Blocka7e24c12009-10-30 11:49:00 +000084Address Top::get_address_from_id(Top::AddressId id) {
85 return top_addresses[id];
86}
87
Steve Block3ce2e202009-11-05 08:53:23 +000088
Steve Blocka7e24c12009-10-30 11:49:00 +000089char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
90 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
91 Iterate(v, thread);
92 return thread_storage + sizeof(ThreadLocalTop);
93}
94
95
Steve Block6ded16b2010-05-10 14:33:55 +010096void Top::IterateThread(ThreadVisitor* v) {
97 v->VisitThread(&thread_local_);
98}
99
100
101void Top::IterateThread(ThreadVisitor* v, char* t) {
102 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
103 v->VisitThread(thread);
104}
105
106
Steve Blocka7e24c12009-10-30 11:49:00 +0000107void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
108 v->VisitPointer(&(thread->pending_exception_));
109 v->VisitPointer(&(thread->pending_message_obj_));
110 v->VisitPointer(
Steve Block6ded16b2010-05-10 14:33:55 +0100111 BitCast<Object**, Script**>(&(thread->pending_message_script_)));
112 v->VisitPointer(BitCast<Object**, Context**>(&(thread->context_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000113 v->VisitPointer(&(thread->scheduled_exception_));
114
Steve Blockd0582a62009-12-15 09:54:21 +0000115 for (v8::TryCatch* block = thread->TryCatchHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000116 block != NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000117 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
Steve Block6ded16b2010-05-10 14:33:55 +0100118 v->VisitPointer(BitCast<Object**, void**>(&(block->exception_)));
119 v->VisitPointer(BitCast<Object**, void**>(&(block->message_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000120 }
121
122 // Iterate over pointers on native execution stack.
123 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
124 it.frame()->Iterate(v);
125 }
126}
127
128
129void Top::Iterate(ObjectVisitor* v) {
130 ThreadLocalTop* current_t = &thread_local_;
131 Iterate(v, current_t);
132}
133
134
135void Top::InitializeThreadLocal() {
Steve Blockd0582a62009-12-15 09:54:21 +0000136 thread_local_.Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +0000137 clear_pending_exception();
138 clear_pending_message();
139 clear_scheduled_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +0000140}
141
142
143// Create a dummy thread that will wait forever on a semaphore. The only
144// purpose for this thread is to have some stack area to save essential data
145// into for use by a stacks only core dump (aka minidump).
146class PreallocatedMemoryThread: public Thread {
147 public:
148 PreallocatedMemoryThread() : keep_running_(true) {
149 wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
150 data_ready_semaphore_ = OS::CreateSemaphore(0);
151 }
152
153 // When the thread starts running it will allocate a fixed number of bytes
154 // on the stack and publish the location of this memory for others to use.
155 void Run() {
156 EmbeddedVector<char, 15 * 1024> local_buffer;
157
158 // Initialize the buffer with a known good value.
159 OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
160 local_buffer.length());
161
162 // Publish the local buffer and signal its availability.
163 data_ = local_buffer.start();
164 length_ = local_buffer.length();
165 data_ready_semaphore_->Signal();
166
167 while (keep_running_) {
168 // This thread will wait here until the end of time.
169 wait_for_ever_semaphore_->Wait();
170 }
171
172 // Make sure we access the buffer after the wait to remove all possibility
173 // of it being optimized away.
174 OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
175 local_buffer.length());
176 }
177
178 static char* data() {
179 if (data_ready_semaphore_ != NULL) {
180 // Initial access is guarded until the data has been published.
181 data_ready_semaphore_->Wait();
182 delete data_ready_semaphore_;
183 data_ready_semaphore_ = NULL;
184 }
185 return data_;
186 }
187
188 static unsigned length() {
189 if (data_ready_semaphore_ != NULL) {
190 // Initial access is guarded until the data has been published.
191 data_ready_semaphore_->Wait();
192 delete data_ready_semaphore_;
193 data_ready_semaphore_ = NULL;
194 }
195 return length_;
196 }
197
198 static void StartThread() {
199 if (the_thread_ != NULL) return;
200
201 the_thread_ = new PreallocatedMemoryThread();
202 the_thread_->Start();
203 }
204
205 // Stop the PreallocatedMemoryThread and release its resources.
206 static void StopThread() {
207 if (the_thread_ == NULL) return;
208
209 the_thread_->keep_running_ = false;
210 wait_for_ever_semaphore_->Signal();
211
212 // Wait for the thread to terminate.
213 the_thread_->Join();
214
215 if (data_ready_semaphore_ != NULL) {
216 delete data_ready_semaphore_;
217 data_ready_semaphore_ = NULL;
218 }
219
220 delete wait_for_ever_semaphore_;
221 wait_for_ever_semaphore_ = NULL;
222
223 // Done with the thread entirely.
224 delete the_thread_;
225 the_thread_ = NULL;
226 }
227
228 private:
229 // Used to make sure that the thread keeps looping even for spurious wakeups.
230 bool keep_running_;
231
232 // The preallocated memory thread singleton.
233 static PreallocatedMemoryThread* the_thread_;
234 // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
235 static Semaphore* wait_for_ever_semaphore_;
236 // Semaphore to signal that the data has been initialized.
237 static Semaphore* data_ready_semaphore_;
238
239 // Location and size of the preallocated memory block.
240 static char* data_;
241 static unsigned length_;
242
243 DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
244};
245
246PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
247Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
248Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
249char* PreallocatedMemoryThread::data_ = NULL;
250unsigned PreallocatedMemoryThread::length_ = 0;
251
252static bool initialized = false;
253
254void Top::Initialize() {
255 CHECK(!initialized);
256
257 InitializeThreadLocal();
258
259 // Only preallocate on the first initialization.
260 if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
261 // Start the thread which will set aside some memory.
262 PreallocatedMemoryThread::StartThread();
263 preallocated_message_space =
264 new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
265 PreallocatedMemoryThread::length());
266 PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
267 }
268 initialized = true;
269}
270
271
272void Top::TearDown() {
273 if (initialized) {
274 // Remove the external reference to the preallocated stack memory.
275 if (preallocated_message_space != NULL) {
276 delete preallocated_message_space;
277 preallocated_message_space = NULL;
278 }
279
280 PreallocatedMemoryThread::StopThread();
281 initialized = false;
282 }
283}
284
285
Steve Blocka7e24c12009-10-30 11:49:00 +0000286void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
Steve Blockd0582a62009-12-15 09:54:21 +0000287 // The ARM simulator has a separate JS stack. We therefore register
288 // the C++ try catch handler with the simulator and get back an
289 // address that can be used for comparisons with addresses into the
290 // JS stack. When running without the simulator, the address
291 // returned will be the address of the C++ try catch handler itself.
292 Address address = reinterpret_cast<Address>(
293 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
294 thread_local_.set_try_catch_handler_address(address);
Steve Blocka7e24c12009-10-30 11:49:00 +0000295}
296
297
298void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
Steve Blockd0582a62009-12-15 09:54:21 +0000299 ASSERT(thread_local_.TryCatchHandler() == that);
300 thread_local_.set_try_catch_handler_address(
301 reinterpret_cast<Address>(that->next_));
Steve Blocka7e24c12009-10-30 11:49:00 +0000302 thread_local_.catcher_ = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000303 SimulatorStack::UnregisterCTryCatch();
Steve Blocka7e24c12009-10-30 11:49:00 +0000304}
305
306
307void Top::MarkCompactPrologue(bool is_compacting) {
308 MarkCompactPrologue(is_compacting, &thread_local_);
309}
310
311
312void Top::MarkCompactPrologue(bool is_compacting, char* data) {
313 MarkCompactPrologue(is_compacting, reinterpret_cast<ThreadLocalTop*>(data));
314}
315
316
317void Top::MarkCompactPrologue(bool is_compacting, ThreadLocalTop* thread) {
318 if (is_compacting) {
319 StackFrame::CookFramesForThread(thread);
320 }
321}
322
323
324void Top::MarkCompactEpilogue(bool is_compacting, char* data) {
325 MarkCompactEpilogue(is_compacting, reinterpret_cast<ThreadLocalTop*>(data));
326}
327
328
329void Top::MarkCompactEpilogue(bool is_compacting) {
330 MarkCompactEpilogue(is_compacting, &thread_local_);
331}
332
333
334void Top::MarkCompactEpilogue(bool is_compacting, ThreadLocalTop* thread) {
335 if (is_compacting) {
336 StackFrame::UncookFramesForThread(thread);
337 }
338}
339
340
341static int stack_trace_nesting_level = 0;
342static StringStream* incomplete_message = NULL;
343
344
Kristian Monsen25f61362010-05-21 11:50:48 +0100345Handle<String> Top::StackTraceString() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 if (stack_trace_nesting_level == 0) {
347 stack_trace_nesting_level++;
348 HeapStringAllocator allocator;
349 StringStream::ClearMentionedObjectCache();
350 StringStream accumulator(&allocator);
351 incomplete_message = &accumulator;
352 PrintStack(&accumulator);
353 Handle<String> stack_trace = accumulator.ToString();
354 incomplete_message = NULL;
355 stack_trace_nesting_level = 0;
356 return stack_trace;
357 } else if (stack_trace_nesting_level == 1) {
358 stack_trace_nesting_level++;
359 OS::PrintError(
360 "\n\nAttempt to print stack while printing stack (double fault)\n");
361 OS::PrintError(
362 "If you are lucky you may find a partial stack dump on stdout.\n\n");
363 incomplete_message->OutputToStdOut();
364 return Factory::empty_symbol();
365 } else {
366 OS::Abort();
367 // Unreachable
368 return Factory::empty_symbol();
369 }
370}
371
372
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100373Handle<JSArray> Top::CaptureCurrentStackTrace(
Kristian Monsen25f61362010-05-21 11:50:48 +0100374 int frame_limit, StackTrace::StackTraceOptions options) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100375 // Ensure no negative values.
376 int limit = Max(frame_limit, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +0100377 Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit);
Kristian Monsen25f61362010-05-21 11:50:48 +0100378
379 Handle<String> column_key = Factory::LookupAsciiSymbol("column");
380 Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber");
381 Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName");
382 Handle<String> function_key = Factory::LookupAsciiSymbol("functionName");
383 Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval");
384 Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor");
385
386 StackTraceFrameIterator it;
387 int frames_seen = 0;
388 while (!it.done() && (frames_seen < limit)) {
389 // Create a JSObject to hold the information for the StackFrame.
390 Handle<JSObject> stackFrame = Factory::NewJSObject(object_function());
391
392 JavaScriptFrame* frame = it.frame();
393 JSFunction* fun(JSFunction::cast(frame->function()));
394 Script* script = Script::cast(fun->shared()->script());
395
396 if (options & StackTrace::kLineNumber) {
397 int script_line_offset = script->line_offset()->value();
398 int position = frame->code()->SourcePosition(frame->pc());
399 int line_number = GetScriptLineNumber(Handle<Script>(script), position);
400 // line_number is already shifted by the script_line_offset.
401 int relative_line_number = line_number - script_line_offset;
402 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
403 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
404 int start = (relative_line_number == 0) ? 0 :
405 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
406 int column_offset = position - start;
407 if (relative_line_number == 0) {
408 // For the case where the code is on the same line as the script tag.
409 column_offset += script->column_offset()->value();
410 }
411 SetProperty(stackFrame, column_key,
412 Handle<Smi>(Smi::FromInt(column_offset + 1)), NONE);
413 }
414 SetProperty(stackFrame, line_key,
415 Handle<Smi>(Smi::FromInt(line_number + 1)), NONE);
416 }
417
418 if (options & StackTrace::kScriptName) {
419 Handle<Object> script_name(script->name());
420 SetProperty(stackFrame, script_key, script_name, NONE);
421 }
422
423 if (options & StackTrace::kFunctionName) {
424 Handle<Object> fun_name(fun->shared()->name());
425 if (fun_name->ToBoolean()->IsFalse()) {
426 fun_name = Handle<Object>(fun->shared()->inferred_name());
427 }
428 SetProperty(stackFrame, function_key, fun_name, NONE);
429 }
430
431 if (options & StackTrace::kIsEval) {
432 int type = Smi::cast(script->compilation_type())->value();
433 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
434 Factory::true_value() : Factory::false_value();
435 SetProperty(stackFrame, eval_key, is_eval, NONE);
436 }
437
438 if (options & StackTrace::kIsConstructor) {
439 Handle<Object> is_constructor = (frame->IsConstructor()) ?
440 Factory::true_value() : Factory::false_value();
441 SetProperty(stackFrame, constructor_key, is_constructor, NONE);
442 }
443
Leon Clarkef7060e22010-06-03 12:02:55 +0100444 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame);
Kristian Monsen25f61362010-05-21 11:50:48 +0100445 frames_seen++;
446 it.Advance();
447 }
448
Leon Clarkef7060e22010-06-03 12:02:55 +0100449 stack_trace->set_length(Smi::FromInt(frames_seen));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100450 return stack_trace;
Kristian Monsen25f61362010-05-21 11:50:48 +0100451}
452
453
Steve Blocka7e24c12009-10-30 11:49:00 +0000454void Top::PrintStack() {
455 if (stack_trace_nesting_level == 0) {
456 stack_trace_nesting_level++;
457
458 StringAllocator* allocator;
459 if (preallocated_message_space == NULL) {
460 allocator = new HeapStringAllocator();
461 } else {
462 allocator = preallocated_message_space;
463 }
464
465 NativeAllocationChecker allocation_checker(
466 !FLAG_preallocate_message_memory ?
467 NativeAllocationChecker::ALLOW :
468 NativeAllocationChecker::DISALLOW);
469
470 StringStream::ClearMentionedObjectCache();
471 StringStream accumulator(allocator);
472 incomplete_message = &accumulator;
473 PrintStack(&accumulator);
474 accumulator.OutputToStdOut();
475 accumulator.Log();
476 incomplete_message = NULL;
477 stack_trace_nesting_level = 0;
478 if (preallocated_message_space == NULL) {
479 // Remove the HeapStringAllocator created above.
480 delete allocator;
481 }
482 } else if (stack_trace_nesting_level == 1) {
483 stack_trace_nesting_level++;
484 OS::PrintError(
485 "\n\nAttempt to print stack while printing stack (double fault)\n");
486 OS::PrintError(
487 "If you are lucky you may find a partial stack dump on stdout.\n\n");
488 incomplete_message->OutputToStdOut();
489 }
490}
491
492
493static void PrintFrames(StringStream* accumulator,
494 StackFrame::PrintMode mode) {
495 StackFrameIterator it;
496 for (int i = 0; !it.done(); it.Advance()) {
497 it.frame()->Print(accumulator, mode, i++);
498 }
499}
500
501
502void Top::PrintStack(StringStream* accumulator) {
503 // The MentionedObjectCache is not GC-proof at the moment.
504 AssertNoAllocation nogc;
505 ASSERT(StringStream::IsMentionedObjectCacheClear());
506
507 // Avoid printing anything if there are no frames.
508 if (c_entry_fp(GetCurrentThread()) == 0) return;
509
510 accumulator->Add(
511 "\n==== Stack trace ============================================\n\n");
512 PrintFrames(accumulator, StackFrame::OVERVIEW);
513
514 accumulator->Add(
515 "\n==== Details ================================================\n\n");
516 PrintFrames(accumulator, StackFrame::DETAILS);
517
518 accumulator->PrintMentionedObjectCache();
519 accumulator->Add("=====================\n\n");
520}
521
522
523void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
524 ASSERT(thread_local_.failed_access_check_callback_ == NULL);
525 thread_local_.failed_access_check_callback_ = callback;
526}
527
528
529void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
530 if (!thread_local_.failed_access_check_callback_) return;
531
532 ASSERT(receiver->IsAccessCheckNeeded());
533 ASSERT(Top::context());
534 // The callers of this method are not expecting a GC.
535 AssertNoAllocation no_gc;
536
537 // Get the data object from access check info.
538 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100539 if (!constructor->shared()->IsApiFunction()) return;
540 Object* data_obj =
541 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000542 if (data_obj == Heap::undefined_value()) return;
543
544 HandleScope scope;
545 Handle<JSObject> receiver_handle(receiver);
546 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
547 thread_local_.failed_access_check_callback_(
548 v8::Utils::ToLocal(receiver_handle),
549 type,
550 v8::Utils::ToLocal(data));
551}
552
553
554enum MayAccessDecision {
555 YES, NO, UNKNOWN
556};
557
558
559static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
560 v8::AccessType type) {
561 // During bootstrapping, callback functions are not enabled yet.
562 if (Bootstrapper::IsActive()) return YES;
563
564 if (receiver->IsJSGlobalProxy()) {
565 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
566 if (!receiver_context->IsContext()) return NO;
567
568 // Get the global context of current top context.
569 // avoid using Top::global_context() because it uses Handle.
570 Context* global_context = Top::context()->global()->global_context();
571 if (receiver_context == global_context) return YES;
572
573 if (Context::cast(receiver_context)->security_token() ==
574 global_context->security_token())
575 return YES;
576 }
577
578 return UNKNOWN;
579}
580
581
582bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
583 ASSERT(receiver->IsAccessCheckNeeded());
Steve Block3ce2e202009-11-05 08:53:23 +0000584
585 // The callers of this method are not expecting a GC.
586 AssertNoAllocation no_gc;
587
588 // Skip checks for hidden properties access. Note, we do not
589 // require existence of a context in this case.
590 if (key == Heap::hidden_symbol()) return true;
591
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 // Check for compatibility between the security tokens in the
593 // current lexical context and the accessed object.
594 ASSERT(Top::context());
Steve Blocka7e24c12009-10-30 11:49:00 +0000595
596 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
597 if (decision != UNKNOWN) return decision == YES;
598
599 // Get named access check callback
600 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100601 if (!constructor->shared()->IsApiFunction()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602
Steve Block6ded16b2010-05-10 14:33:55 +0100603 Object* data_obj =
604 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000605 if (data_obj == Heap::undefined_value()) return false;
606
607 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
608 v8::NamedSecurityCallback callback =
609 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
610
611 if (!callback) return false;
612
613 HandleScope scope;
614 Handle<JSObject> receiver_handle(receiver);
615 Handle<Object> key_handle(key);
616 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
617 LOG(ApiNamedSecurityCheck(key));
618 bool result = false;
619 {
620 // Leaving JavaScript.
621 VMState state(EXTERNAL);
622 result = callback(v8::Utils::ToLocal(receiver_handle),
623 v8::Utils::ToLocal(key_handle),
624 type,
625 v8::Utils::ToLocal(data));
626 }
627 return result;
628}
629
630
631bool Top::MayIndexedAccess(JSObject* receiver,
632 uint32_t index,
633 v8::AccessType type) {
634 ASSERT(receiver->IsAccessCheckNeeded());
635 // Check for compatibility between the security tokens in the
636 // current lexical context and the accessed object.
637 ASSERT(Top::context());
638 // The callers of this method are not expecting a GC.
639 AssertNoAllocation no_gc;
640
641 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
642 if (decision != UNKNOWN) return decision == YES;
643
644 // Get indexed access check callback
645 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100646 if (!constructor->shared()->IsApiFunction()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000647
Steve Block6ded16b2010-05-10 14:33:55 +0100648 Object* data_obj =
649 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 if (data_obj == Heap::undefined_value()) return false;
651
652 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
653 v8::IndexedSecurityCallback callback =
654 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
655
656 if (!callback) return false;
657
658 HandleScope scope;
659 Handle<JSObject> receiver_handle(receiver);
660 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
661 LOG(ApiIndexedSecurityCheck(index));
662 bool result = false;
663 {
664 // Leaving JavaScript.
665 VMState state(EXTERNAL);
666 result = callback(v8::Utils::ToLocal(receiver_handle),
667 index,
668 type,
669 v8::Utils::ToLocal(data));
670 }
671 return result;
672}
673
674
675const char* Top::kStackOverflowMessage =
676 "Uncaught RangeError: Maximum call stack size exceeded";
677
678
679Failure* Top::StackOverflow() {
680 HandleScope scope;
681 Handle<String> key = Factory::stack_overflow_symbol();
682 Handle<JSObject> boilerplate =
683 Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
684 Handle<Object> exception = Copy(boilerplate);
685 // TODO(1240995): To avoid having to call JavaScript code to compute
686 // the message for stack overflow exceptions which is very likely to
687 // double fault with another stack overflow exception, we use a
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100688 // precomputed message.
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 DoThrow(*exception, NULL, kStackOverflowMessage);
690 return Failure::Exception();
691}
692
693
694Failure* Top::TerminateExecution() {
695 DoThrow(Heap::termination_exception(), NULL, NULL);
696 return Failure::Exception();
697}
698
699
700Failure* Top::Throw(Object* exception, MessageLocation* location) {
701 DoThrow(exception, location, NULL);
702 return Failure::Exception();
703}
704
705
706Failure* Top::ReThrow(Object* exception, MessageLocation* location) {
707 // Set the exception being re-thrown.
708 set_pending_exception(exception);
709 return Failure::Exception();
710}
711
712
713Failure* Top::ThrowIllegalOperation() {
714 return Throw(Heap::illegal_access_symbol());
715}
716
717
718void Top::ScheduleThrow(Object* exception) {
719 // When scheduling a throw we first throw the exception to get the
720 // error reporting if it is uncaught before rescheduling it.
721 Throw(exception);
722 thread_local_.scheduled_exception_ = pending_exception();
723 thread_local_.external_caught_exception_ = false;
724 clear_pending_exception();
725}
726
727
728Object* Top::PromoteScheduledException() {
729 Object* thrown = scheduled_exception();
730 clear_scheduled_exception();
731 // Re-throw the exception to avoid getting repeated error reporting.
732 return ReThrow(thrown);
733}
734
735
736void Top::PrintCurrentStackTrace(FILE* out) {
737 StackTraceFrameIterator it;
738 while (!it.done()) {
739 HandleScope scope;
740 // Find code position if recorded in relocation info.
741 JavaScriptFrame* frame = it.frame();
742 int pos = frame->code()->SourcePosition(frame->pc());
743 Handle<Object> pos_obj(Smi::FromInt(pos));
744 // Fetch function and receiver.
745 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
746 Handle<Object> recv(frame->receiver());
747 // Advance to the next JavaScript frame and determine if the
748 // current frame is the top-level frame.
749 it.Advance();
750 Handle<Object> is_top_level = it.done()
751 ? Factory::true_value()
752 : Factory::false_value();
753 // Generate and print stack trace line.
754 Handle<String> line =
755 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
756 if (line->length() > 0) {
757 line->PrintOn(out);
758 fprintf(out, "\n");
759 }
760 }
761}
762
763
764void Top::ComputeLocation(MessageLocation* target) {
Andrei Popescu31002712010-02-23 13:46:05 +0000765 *target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000766 StackTraceFrameIterator it;
767 if (!it.done()) {
768 JavaScriptFrame* frame = it.frame();
769 JSFunction* fun = JSFunction::cast(frame->function());
770 Object* script = fun->shared()->script();
771 if (script->IsScript() &&
772 !(Script::cast(script)->source()->IsUndefined())) {
773 int pos = frame->code()->SourcePosition(frame->pc());
774 // Compute the location from the function and the reloc info.
775 Handle<Script> casted_script(Script::cast(script));
776 *target = MessageLocation(casted_script, pos, pos + 1);
777 }
778 }
779}
780
781
Steve Blocka7e24c12009-10-30 11:49:00 +0000782bool Top::ShouldReturnException(bool* is_caught_externally,
783 bool catchable_by_javascript) {
784 // Find the top-most try-catch handler.
785 StackHandler* handler =
786 StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
787 while (handler != NULL && !handler->is_try_catch()) {
788 handler = handler->next();
789 }
790
791 // Get the address of the external handler so we can compare the address to
792 // determine which one is closer to the top of the stack.
Steve Blockd0582a62009-12-15 09:54:21 +0000793 Address external_handler_address = thread_local_.try_catch_handler_address();
Steve Blocka7e24c12009-10-30 11:49:00 +0000794
795 // The exception has been externally caught if and only if there is
796 // an external handler which is on top of the top-most try-catch
797 // handler.
Steve Blockd0582a62009-12-15 09:54:21 +0000798 *is_caught_externally = external_handler_address != NULL &&
799 (handler == NULL || handler->address() > external_handler_address ||
Steve Blocka7e24c12009-10-30 11:49:00 +0000800 !catchable_by_javascript);
801
802 if (*is_caught_externally) {
803 // Only report the exception if the external handler is verbose.
Steve Blockd0582a62009-12-15 09:54:21 +0000804 return thread_local_.TryCatchHandler()->is_verbose_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 } else {
806 // Report the exception if it isn't caught by JavaScript code.
807 return handler == NULL;
808 }
809}
810
811
812void Top::DoThrow(Object* exception,
813 MessageLocation* location,
814 const char* message) {
815 ASSERT(!has_pending_exception());
816
817 HandleScope scope;
818 Handle<Object> exception_handle(exception);
819
820 // Determine reporting and whether the exception is caught externally.
821 bool is_caught_externally = false;
822 bool is_out_of_memory = exception == Failure::OutOfMemoryException();
823 bool is_termination_exception = exception == Heap::termination_exception();
824 bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory;
825 bool should_return_exception =
826 ShouldReturnException(&is_caught_externally, catchable_by_javascript);
827 bool report_exception = catchable_by_javascript && should_return_exception;
828
829#ifdef ENABLE_DEBUGGER_SUPPORT
830 // Notify debugger of exception.
831 if (catchable_by_javascript) {
832 Debugger::OnException(exception_handle, report_exception);
833 }
834#endif
835
836 // Generate the message.
837 Handle<Object> message_obj;
838 MessageLocation potential_computed_location;
839 bool try_catch_needs_message =
840 is_caught_externally &&
Steve Blockd0582a62009-12-15 09:54:21 +0000841 thread_local_.TryCatchHandler()->capture_message_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000842 if (report_exception || try_catch_needs_message) {
843 if (location == NULL) {
844 // If no location was specified we use a computed one instead
845 ComputeLocation(&potential_computed_location);
846 location = &potential_computed_location;
847 }
848 if (!Bootstrapper::IsActive()) {
849 // It's not safe to try to make message objects or collect stack
850 // traces while the bootstrapper is active since the infrastructure
851 // may not have been properly initialized.
852 Handle<String> stack_trace;
Kristian Monsen25f61362010-05-21 11:50:48 +0100853 if (FLAG_trace_exception) stack_trace = StackTraceString();
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100854 Handle<JSArray> stack_trace_object;
855 if (report_exception && capture_stack_trace_for_uncaught_exceptions) {
856 stack_trace_object = Top::CaptureCurrentStackTrace(
857 stack_trace_for_uncaught_exceptions_frame_limit,
858 stack_trace_for_uncaught_exceptions_options);
859 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000860 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100861 location, HandleVector<Object>(&exception_handle, 1), stack_trace,
862 stack_trace_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000863 }
864 }
865
866 // Save the message for reporting if the the exception remains uncaught.
867 thread_local_.has_pending_message_ = report_exception;
868 thread_local_.pending_message_ = message;
869 if (!message_obj.is_null()) {
870 thread_local_.pending_message_obj_ = *message_obj;
871 if (location != NULL) {
872 thread_local_.pending_message_script_ = *location->script();
873 thread_local_.pending_message_start_pos_ = location->start_pos();
874 thread_local_.pending_message_end_pos_ = location->end_pos();
875 }
876 }
877
878 if (is_caught_externally) {
Steve Blockd0582a62009-12-15 09:54:21 +0000879 thread_local_.catcher_ = thread_local_.TryCatchHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 }
881
882 // NOTE: Notifying the debugger or generating the message
883 // may have caused new exceptions. For now, we just ignore
884 // that and set the pending exception to the original one.
885 set_pending_exception(*exception_handle);
886}
887
888
889void Top::ReportPendingMessages() {
890 ASSERT(has_pending_exception());
891 setup_external_caught();
892 // If the pending exception is OutOfMemoryException set out_of_memory in
893 // the global context. Note: We have to mark the global context here
894 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
895 // set it.
896 bool external_caught = thread_local_.external_caught_exception_;
897 HandleScope scope;
898 if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
899 context()->mark_out_of_memory();
900 } else if (thread_local_.pending_exception_ ==
901 Heap::termination_exception()) {
902 if (external_caught) {
Steve Blockd0582a62009-12-15 09:54:21 +0000903 thread_local_.TryCatchHandler()->can_continue_ = false;
904 thread_local_.TryCatchHandler()->exception_ = Heap::null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000905 }
906 } else {
907 Handle<Object> exception(pending_exception());
908 thread_local_.external_caught_exception_ = false;
909 if (external_caught) {
Steve Blockd0582a62009-12-15 09:54:21 +0000910 thread_local_.TryCatchHandler()->can_continue_ = true;
911 thread_local_.TryCatchHandler()->exception_ =
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 thread_local_.pending_exception_;
913 if (!thread_local_.pending_message_obj_->IsTheHole()) {
914 try_catch_handler()->message_ = thread_local_.pending_message_obj_;
915 }
916 }
917 if (thread_local_.has_pending_message_) {
918 thread_local_.has_pending_message_ = false;
919 if (thread_local_.pending_message_ != NULL) {
920 MessageHandler::ReportMessage(thread_local_.pending_message_);
921 } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
922 Handle<Object> message_obj(thread_local_.pending_message_obj_);
923 if (thread_local_.pending_message_script_ != NULL) {
924 Handle<Script> script(thread_local_.pending_message_script_);
925 int start_pos = thread_local_.pending_message_start_pos_;
926 int end_pos = thread_local_.pending_message_end_pos_;
927 MessageLocation location(script, start_pos, end_pos);
928 MessageHandler::ReportMessage(&location, message_obj);
929 } else {
930 MessageHandler::ReportMessage(NULL, message_obj);
931 }
932 }
933 }
934 thread_local_.external_caught_exception_ = external_caught;
935 set_pending_exception(*exception);
936 }
937 clear_pending_message();
938}
939
940
941void Top::TraceException(bool flag) {
942 FLAG_trace_exception = flag;
943}
944
945
946bool Top::OptionalRescheduleException(bool is_bottom_call) {
947 // Allways reschedule out of memory exceptions.
948 if (!is_out_of_memory()) {
949 bool is_termination_exception =
950 pending_exception() == Heap::termination_exception();
951
952 // Do not reschedule the exception if this is the bottom call.
953 bool clear_exception = is_bottom_call;
954
955 if (is_termination_exception) {
956 if (is_bottom_call) {
957 thread_local_.external_caught_exception_ = false;
958 clear_pending_exception();
959 return false;
960 }
961 } else if (thread_local_.external_caught_exception_) {
962 // If the exception is externally caught, clear it if there are no
963 // JavaScript frames on the way to the C++ frame that has the
964 // external handler.
Steve Blockd0582a62009-12-15 09:54:21 +0000965 ASSERT(thread_local_.try_catch_handler_address() != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000966 Address external_handler_address =
Steve Blockd0582a62009-12-15 09:54:21 +0000967 thread_local_.try_catch_handler_address();
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 JavaScriptFrameIterator it;
969 if (it.done() || (it.frame()->sp() > external_handler_address)) {
970 clear_exception = true;
971 }
972 }
973
974 // Clear the exception if needed.
975 if (clear_exception) {
976 thread_local_.external_caught_exception_ = false;
977 clear_pending_exception();
978 return false;
979 }
980 }
981
982 // Reschedule the exception.
983 thread_local_.scheduled_exception_ = pending_exception();
984 clear_pending_exception();
985 return true;
986}
987
988
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100989void Top::SetCaptureStackTraceForUncaughtExceptions(
990 bool capture,
991 int frame_limit,
992 StackTrace::StackTraceOptions options) {
993 capture_stack_trace_for_uncaught_exceptions = capture;
994 stack_trace_for_uncaught_exceptions_frame_limit = frame_limit;
995 stack_trace_for_uncaught_exceptions_options = options;
996}
997
998
Steve Blocka7e24c12009-10-30 11:49:00 +0000999bool Top::is_out_of_memory() {
1000 if (has_pending_exception()) {
1001 Object* e = pending_exception();
1002 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1003 return true;
1004 }
1005 }
1006 if (has_scheduled_exception()) {
1007 Object* e = scheduled_exception();
1008 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1009 return true;
1010 }
1011 }
1012 return false;
1013}
1014
1015
1016Handle<Context> Top::global_context() {
1017 GlobalObject* global = thread_local_.context_->global();
1018 return Handle<Context>(global->global_context());
1019}
1020
1021
1022Handle<Context> Top::GetCallingGlobalContext() {
1023 JavaScriptFrameIterator it;
Steve Blockd0582a62009-12-15 09:54:21 +00001024#ifdef ENABLE_DEBUGGER_SUPPORT
1025 if (Debug::InDebugger()) {
1026 while (!it.done()) {
1027 JavaScriptFrame* frame = it.frame();
1028 Context* context = Context::cast(frame->context());
1029 if (context->global_context() == *Debug::debug_context()) {
1030 it.Advance();
1031 } else {
1032 break;
1033 }
1034 }
1035 }
1036#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +00001037 if (it.done()) return Handle<Context>::null();
1038 JavaScriptFrame* frame = it.frame();
1039 Context* context = Context::cast(frame->context());
1040 return Handle<Context>(context->global_context());
1041}
1042
1043
Steve Blocka7e24c12009-10-30 11:49:00 +00001044char* Top::ArchiveThread(char* to) {
1045 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
1046 InitializeThreadLocal();
1047 return to + sizeof(thread_local_);
1048}
1049
1050
1051char* Top::RestoreThread(char* from) {
1052 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
1053 return from + sizeof(thread_local_);
1054}
1055
1056
1057ExecutionAccess::ExecutionAccess() {
1058 Top::break_access_->Lock();
1059}
1060
1061
1062ExecutionAccess::~ExecutionAccess() {
1063 Top::break_access_->Unlock();
1064}
1065
1066
1067} } // namespace v8::internal