blob: 9ce65429642d26e1bc027e5345d0ed362e3ce6f8 [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
Ben Murdochf87a2032010-10-22 12:50:53 +010072#ifdef ENABLE_VMSTATE_TRACKING
73 current_vm_state_ = NULL;
74#endif
Steve Blockd0582a62009-12-15 09:54:21 +000075 try_catch_handler_address_ = NULL;
76 context_ = NULL;
77 int id = ThreadManager::CurrentId();
78 thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
79 external_caught_exception_ = false;
80 failed_access_check_callback_ = NULL;
81 save_context_ = NULL;
82 catcher_ = NULL;
83}
84
85
Steve Blocka7e24c12009-10-30 11:49:00 +000086Address Top::get_address_from_id(Top::AddressId id) {
87 return top_addresses[id];
88}
89
Steve Block3ce2e202009-11-05 08:53:23 +000090
Steve Blocka7e24c12009-10-30 11:49:00 +000091char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
92 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
93 Iterate(v, thread);
94 return thread_storage + sizeof(ThreadLocalTop);
95}
96
97
Steve Block6ded16b2010-05-10 14:33:55 +010098void Top::IterateThread(ThreadVisitor* v) {
99 v->VisitThread(&thread_local_);
100}
101
102
103void Top::IterateThread(ThreadVisitor* v, char* t) {
104 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
105 v->VisitThread(thread);
106}
107
108
Steve Blocka7e24c12009-10-30 11:49:00 +0000109void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
110 v->VisitPointer(&(thread->pending_exception_));
111 v->VisitPointer(&(thread->pending_message_obj_));
Iain Merrick75681382010-08-19 15:07:18 +0100112 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_)));
113 v->VisitPointer(BitCast<Object**>(&(thread->context_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000114 v->VisitPointer(&(thread->scheduled_exception_));
115
Steve Blockd0582a62009-12-15 09:54:21 +0000116 for (v8::TryCatch* block = thread->TryCatchHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000117 block != NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000118 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
Iain Merrick75681382010-08-19 15:07:18 +0100119 v->VisitPointer(BitCast<Object**>(&(block->exception_)));
120 v->VisitPointer(BitCast<Object**>(&(block->message_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000121 }
122
123 // Iterate over pointers on native execution stack.
124 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
125 it.frame()->Iterate(v);
126 }
127}
128
129
130void Top::Iterate(ObjectVisitor* v) {
131 ThreadLocalTop* current_t = &thread_local_;
132 Iterate(v, current_t);
133}
134
135
136void Top::InitializeThreadLocal() {
Steve Blockd0582a62009-12-15 09:54:21 +0000137 thread_local_.Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +0000138 clear_pending_exception();
139 clear_pending_message();
140 clear_scheduled_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +0000141}
142
143
144// Create a dummy thread that will wait forever on a semaphore. The only
145// purpose for this thread is to have some stack area to save essential data
146// into for use by a stacks only core dump (aka minidump).
147class PreallocatedMemoryThread: public Thread {
148 public:
149 PreallocatedMemoryThread() : keep_running_(true) {
150 wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
151 data_ready_semaphore_ = OS::CreateSemaphore(0);
152 }
153
154 // When the thread starts running it will allocate a fixed number of bytes
155 // on the stack and publish the location of this memory for others to use.
156 void Run() {
157 EmbeddedVector<char, 15 * 1024> local_buffer;
158
159 // Initialize the buffer with a known good value.
160 OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
161 local_buffer.length());
162
163 // Publish the local buffer and signal its availability.
164 data_ = local_buffer.start();
165 length_ = local_buffer.length();
166 data_ready_semaphore_->Signal();
167
168 while (keep_running_) {
169 // This thread will wait here until the end of time.
170 wait_for_ever_semaphore_->Wait();
171 }
172
173 // Make sure we access the buffer after the wait to remove all possibility
174 // of it being optimized away.
175 OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
176 local_buffer.length());
177 }
178
179 static char* data() {
180 if (data_ready_semaphore_ != NULL) {
181 // Initial access is guarded until the data has been published.
182 data_ready_semaphore_->Wait();
183 delete data_ready_semaphore_;
184 data_ready_semaphore_ = NULL;
185 }
186 return data_;
187 }
188
189 static unsigned length() {
190 if (data_ready_semaphore_ != NULL) {
191 // Initial access is guarded until the data has been published.
192 data_ready_semaphore_->Wait();
193 delete data_ready_semaphore_;
194 data_ready_semaphore_ = NULL;
195 }
196 return length_;
197 }
198
199 static void StartThread() {
200 if (the_thread_ != NULL) return;
201
202 the_thread_ = new PreallocatedMemoryThread();
203 the_thread_->Start();
204 }
205
206 // Stop the PreallocatedMemoryThread and release its resources.
207 static void StopThread() {
208 if (the_thread_ == NULL) return;
209
210 the_thread_->keep_running_ = false;
211 wait_for_ever_semaphore_->Signal();
212
213 // Wait for the thread to terminate.
214 the_thread_->Join();
215
216 if (data_ready_semaphore_ != NULL) {
217 delete data_ready_semaphore_;
218 data_ready_semaphore_ = NULL;
219 }
220
221 delete wait_for_ever_semaphore_;
222 wait_for_ever_semaphore_ = NULL;
223
224 // Done with the thread entirely.
225 delete the_thread_;
226 the_thread_ = NULL;
227 }
228
229 private:
230 // Used to make sure that the thread keeps looping even for spurious wakeups.
231 bool keep_running_;
232
233 // The preallocated memory thread singleton.
234 static PreallocatedMemoryThread* the_thread_;
235 // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
236 static Semaphore* wait_for_ever_semaphore_;
237 // Semaphore to signal that the data has been initialized.
238 static Semaphore* data_ready_semaphore_;
239
240 // Location and size of the preallocated memory block.
241 static char* data_;
242 static unsigned length_;
243
244 DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
245};
246
247PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
248Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
249Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
250char* PreallocatedMemoryThread::data_ = NULL;
251unsigned PreallocatedMemoryThread::length_ = 0;
252
253static bool initialized = false;
254
255void Top::Initialize() {
256 CHECK(!initialized);
257
258 InitializeThreadLocal();
259
260 // Only preallocate on the first initialization.
261 if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
262 // Start the thread which will set aside some memory.
263 PreallocatedMemoryThread::StartThread();
264 preallocated_message_space =
265 new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
266 PreallocatedMemoryThread::length());
267 PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
268 }
269 initialized = true;
270}
271
272
273void Top::TearDown() {
274 if (initialized) {
275 // Remove the external reference to the preallocated stack memory.
276 if (preallocated_message_space != NULL) {
277 delete preallocated_message_space;
278 preallocated_message_space = NULL;
279 }
280
281 PreallocatedMemoryThread::StopThread();
282 initialized = false;
283 }
284}
285
286
Steve Blocka7e24c12009-10-30 11:49:00 +0000287void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
Steve Blockd0582a62009-12-15 09:54:21 +0000288 // The ARM simulator has a separate JS stack. We therefore register
289 // the C++ try catch handler with the simulator and get back an
290 // address that can be used for comparisons with addresses into the
291 // JS stack. When running without the simulator, the address
292 // returned will be the address of the C++ try catch handler itself.
293 Address address = reinterpret_cast<Address>(
294 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
295 thread_local_.set_try_catch_handler_address(address);
Steve Blocka7e24c12009-10-30 11:49:00 +0000296}
297
298
299void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
Steve Blockd0582a62009-12-15 09:54:21 +0000300 ASSERT(thread_local_.TryCatchHandler() == that);
301 thread_local_.set_try_catch_handler_address(
302 reinterpret_cast<Address>(that->next_));
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 thread_local_.catcher_ = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000304 SimulatorStack::UnregisterCTryCatch();
Steve Blocka7e24c12009-10-30 11:49:00 +0000305}
306
307
Steve Blocka7e24c12009-10-30 11:49:00 +0000308
309static int stack_trace_nesting_level = 0;
310static StringStream* incomplete_message = NULL;
311
312
Kristian Monsen25f61362010-05-21 11:50:48 +0100313Handle<String> Top::StackTraceString() {
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 if (stack_trace_nesting_level == 0) {
315 stack_trace_nesting_level++;
316 HeapStringAllocator allocator;
317 StringStream::ClearMentionedObjectCache();
318 StringStream accumulator(&allocator);
319 incomplete_message = &accumulator;
320 PrintStack(&accumulator);
321 Handle<String> stack_trace = accumulator.ToString();
322 incomplete_message = NULL;
323 stack_trace_nesting_level = 0;
324 return stack_trace;
325 } else if (stack_trace_nesting_level == 1) {
326 stack_trace_nesting_level++;
327 OS::PrintError(
328 "\n\nAttempt to print stack while printing stack (double fault)\n");
329 OS::PrintError(
330 "If you are lucky you may find a partial stack dump on stdout.\n\n");
331 incomplete_message->OutputToStdOut();
332 return Factory::empty_symbol();
333 } else {
334 OS::Abort();
335 // Unreachable
336 return Factory::empty_symbol();
337 }
338}
339
340
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100341Handle<JSArray> Top::CaptureCurrentStackTrace(
Kristian Monsen25f61362010-05-21 11:50:48 +0100342 int frame_limit, StackTrace::StackTraceOptions options) {
Kristian Monsen25f61362010-05-21 11:50:48 +0100343 // Ensure no negative values.
344 int limit = Max(frame_limit, 0);
Leon Clarkef7060e22010-06-03 12:02:55 +0100345 Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit);
Kristian Monsen25f61362010-05-21 11:50:48 +0100346
347 Handle<String> column_key = Factory::LookupAsciiSymbol("column");
348 Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber");
349 Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName");
Ben Murdochf87a2032010-10-22 12:50:53 +0100350 Handle<String> name_or_source_url_key =
351 Factory::LookupAsciiSymbol("nameOrSourceURL");
352 Handle<String> script_name_or_source_url_key =
353 Factory::LookupAsciiSymbol("scriptNameOrSourceURL");
Kristian Monsen25f61362010-05-21 11:50:48 +0100354 Handle<String> function_key = Factory::LookupAsciiSymbol("functionName");
355 Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval");
356 Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor");
357
358 StackTraceFrameIterator it;
359 int frames_seen = 0;
360 while (!it.done() && (frames_seen < limit)) {
361 // Create a JSObject to hold the information for the StackFrame.
362 Handle<JSObject> stackFrame = Factory::NewJSObject(object_function());
363
364 JavaScriptFrame* frame = it.frame();
Ben Murdochf87a2032010-10-22 12:50:53 +0100365 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
366 Handle<Script> script(Script::cast(fun->shared()->script()));
Kristian Monsen25f61362010-05-21 11:50:48 +0100367
368 if (options & StackTrace::kLineNumber) {
369 int script_line_offset = script->line_offset()->value();
370 int position = frame->code()->SourcePosition(frame->pc());
Ben Murdochf87a2032010-10-22 12:50:53 +0100371 int line_number = GetScriptLineNumber(script, position);
Kristian Monsen25f61362010-05-21 11:50:48 +0100372 // line_number is already shifted by the script_line_offset.
373 int relative_line_number = line_number - script_line_offset;
374 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
375 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
376 int start = (relative_line_number == 0) ? 0 :
377 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
378 int column_offset = position - start;
379 if (relative_line_number == 0) {
380 // For the case where the code is on the same line as the script tag.
381 column_offset += script->column_offset()->value();
382 }
383 SetProperty(stackFrame, column_key,
384 Handle<Smi>(Smi::FromInt(column_offset + 1)), NONE);
385 }
386 SetProperty(stackFrame, line_key,
387 Handle<Smi>(Smi::FromInt(line_number + 1)), NONE);
388 }
389
390 if (options & StackTrace::kScriptName) {
391 Handle<Object> script_name(script->name());
392 SetProperty(stackFrame, script_key, script_name, NONE);
393 }
394
Ben Murdochf87a2032010-10-22 12:50:53 +0100395 if (options & StackTrace::kScriptNameOrSourceURL) {
396 Handle<Object> script_name(script->name());
397 Handle<JSValue> script_wrapper = GetScriptWrapper(script);
398 Handle<Object> property = GetProperty(script_wrapper,
399 name_or_source_url_key);
400 ASSERT(property->IsJSFunction());
401 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
402 bool caught_exception;
403 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
404 NULL, &caught_exception);
405 if (caught_exception) {
406 result = Factory::undefined_value();
407 }
408 SetProperty(stackFrame, script_name_or_source_url_key, result, NONE);
409 }
410
Kristian Monsen25f61362010-05-21 11:50:48 +0100411 if (options & StackTrace::kFunctionName) {
412 Handle<Object> fun_name(fun->shared()->name());
413 if (fun_name->ToBoolean()->IsFalse()) {
414 fun_name = Handle<Object>(fun->shared()->inferred_name());
415 }
416 SetProperty(stackFrame, function_key, fun_name, NONE);
417 }
418
419 if (options & StackTrace::kIsEval) {
420 int type = Smi::cast(script->compilation_type())->value();
421 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
422 Factory::true_value() : Factory::false_value();
423 SetProperty(stackFrame, eval_key, is_eval, NONE);
424 }
425
426 if (options & StackTrace::kIsConstructor) {
427 Handle<Object> is_constructor = (frame->IsConstructor()) ?
428 Factory::true_value() : Factory::false_value();
429 SetProperty(stackFrame, constructor_key, is_constructor, NONE);
430 }
431
Leon Clarkef7060e22010-06-03 12:02:55 +0100432 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame);
Kristian Monsen25f61362010-05-21 11:50:48 +0100433 frames_seen++;
434 it.Advance();
435 }
436
Leon Clarkef7060e22010-06-03 12:02:55 +0100437 stack_trace->set_length(Smi::FromInt(frames_seen));
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100438 return stack_trace;
Kristian Monsen25f61362010-05-21 11:50:48 +0100439}
440
441
Steve Blocka7e24c12009-10-30 11:49:00 +0000442void Top::PrintStack() {
443 if (stack_trace_nesting_level == 0) {
444 stack_trace_nesting_level++;
445
446 StringAllocator* allocator;
447 if (preallocated_message_space == NULL) {
448 allocator = new HeapStringAllocator();
449 } else {
450 allocator = preallocated_message_space;
451 }
452
453 NativeAllocationChecker allocation_checker(
454 !FLAG_preallocate_message_memory ?
455 NativeAllocationChecker::ALLOW :
456 NativeAllocationChecker::DISALLOW);
457
458 StringStream::ClearMentionedObjectCache();
459 StringStream accumulator(allocator);
460 incomplete_message = &accumulator;
461 PrintStack(&accumulator);
462 accumulator.OutputToStdOut();
463 accumulator.Log();
464 incomplete_message = NULL;
465 stack_trace_nesting_level = 0;
466 if (preallocated_message_space == NULL) {
467 // Remove the HeapStringAllocator created above.
468 delete allocator;
469 }
470 } else if (stack_trace_nesting_level == 1) {
471 stack_trace_nesting_level++;
472 OS::PrintError(
473 "\n\nAttempt to print stack while printing stack (double fault)\n");
474 OS::PrintError(
475 "If you are lucky you may find a partial stack dump on stdout.\n\n");
476 incomplete_message->OutputToStdOut();
477 }
478}
479
480
481static void PrintFrames(StringStream* accumulator,
482 StackFrame::PrintMode mode) {
483 StackFrameIterator it;
484 for (int i = 0; !it.done(); it.Advance()) {
485 it.frame()->Print(accumulator, mode, i++);
486 }
487}
488
489
490void Top::PrintStack(StringStream* accumulator) {
491 // The MentionedObjectCache is not GC-proof at the moment.
492 AssertNoAllocation nogc;
493 ASSERT(StringStream::IsMentionedObjectCacheClear());
494
495 // Avoid printing anything if there are no frames.
496 if (c_entry_fp(GetCurrentThread()) == 0) return;
497
498 accumulator->Add(
499 "\n==== Stack trace ============================================\n\n");
500 PrintFrames(accumulator, StackFrame::OVERVIEW);
501
502 accumulator->Add(
503 "\n==== Details ================================================\n\n");
504 PrintFrames(accumulator, StackFrame::DETAILS);
505
506 accumulator->PrintMentionedObjectCache();
507 accumulator->Add("=====================\n\n");
508}
509
510
511void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000512 thread_local_.failed_access_check_callback_ = callback;
513}
514
515
516void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
517 if (!thread_local_.failed_access_check_callback_) return;
518
519 ASSERT(receiver->IsAccessCheckNeeded());
520 ASSERT(Top::context());
Steve Blocka7e24c12009-10-30 11:49:00 +0000521
522 // Get the data object from access check info.
523 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100524 if (!constructor->shared()->IsApiFunction()) return;
525 Object* data_obj =
526 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 if (data_obj == Heap::undefined_value()) return;
528
529 HandleScope scope;
530 Handle<JSObject> receiver_handle(receiver);
531 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
532 thread_local_.failed_access_check_callback_(
533 v8::Utils::ToLocal(receiver_handle),
534 type,
535 v8::Utils::ToLocal(data));
536}
537
538
539enum MayAccessDecision {
540 YES, NO, UNKNOWN
541};
542
543
544static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
545 v8::AccessType type) {
546 // During bootstrapping, callback functions are not enabled yet.
547 if (Bootstrapper::IsActive()) return YES;
548
549 if (receiver->IsJSGlobalProxy()) {
550 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
551 if (!receiver_context->IsContext()) return NO;
552
553 // Get the global context of current top context.
554 // avoid using Top::global_context() because it uses Handle.
555 Context* global_context = Top::context()->global()->global_context();
556 if (receiver_context == global_context) return YES;
557
558 if (Context::cast(receiver_context)->security_token() ==
559 global_context->security_token())
560 return YES;
561 }
562
563 return UNKNOWN;
564}
565
566
567bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
568 ASSERT(receiver->IsAccessCheckNeeded());
Steve Block3ce2e202009-11-05 08:53:23 +0000569
570 // The callers of this method are not expecting a GC.
571 AssertNoAllocation no_gc;
572
573 // Skip checks for hidden properties access. Note, we do not
574 // require existence of a context in this case.
575 if (key == Heap::hidden_symbol()) return true;
576
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 // Check for compatibility between the security tokens in the
578 // current lexical context and the accessed object.
579 ASSERT(Top::context());
Steve Blocka7e24c12009-10-30 11:49:00 +0000580
581 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
582 if (decision != UNKNOWN) return decision == YES;
583
584 // Get named access check callback
585 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100586 if (!constructor->shared()->IsApiFunction()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000587
Steve Block6ded16b2010-05-10 14:33:55 +0100588 Object* data_obj =
589 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 if (data_obj == Heap::undefined_value()) return false;
591
592 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
593 v8::NamedSecurityCallback callback =
594 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
595
596 if (!callback) return false;
597
598 HandleScope scope;
599 Handle<JSObject> receiver_handle(receiver);
600 Handle<Object> key_handle(key);
601 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
602 LOG(ApiNamedSecurityCheck(key));
603 bool result = false;
604 {
605 // Leaving JavaScript.
606 VMState state(EXTERNAL);
607 result = callback(v8::Utils::ToLocal(receiver_handle),
608 v8::Utils::ToLocal(key_handle),
609 type,
610 v8::Utils::ToLocal(data));
611 }
612 return result;
613}
614
615
616bool Top::MayIndexedAccess(JSObject* receiver,
617 uint32_t index,
618 v8::AccessType type) {
619 ASSERT(receiver->IsAccessCheckNeeded());
620 // Check for compatibility between the security tokens in the
621 // current lexical context and the accessed object.
622 ASSERT(Top::context());
623 // The callers of this method are not expecting a GC.
624 AssertNoAllocation no_gc;
625
626 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
627 if (decision != UNKNOWN) return decision == YES;
628
629 // Get indexed access check callback
630 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
Steve Block6ded16b2010-05-10 14:33:55 +0100631 if (!constructor->shared()->IsApiFunction()) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000632
Steve Block6ded16b2010-05-10 14:33:55 +0100633 Object* data_obj =
634 constructor->shared()->get_api_func_data()->access_check_info();
Steve Blocka7e24c12009-10-30 11:49:00 +0000635 if (data_obj == Heap::undefined_value()) return false;
636
637 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
638 v8::IndexedSecurityCallback callback =
639 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
640
641 if (!callback) return false;
642
643 HandleScope scope;
644 Handle<JSObject> receiver_handle(receiver);
645 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
646 LOG(ApiIndexedSecurityCheck(index));
647 bool result = false;
648 {
649 // Leaving JavaScript.
650 VMState state(EXTERNAL);
651 result = callback(v8::Utils::ToLocal(receiver_handle),
652 index,
653 type,
654 v8::Utils::ToLocal(data));
655 }
656 return result;
657}
658
659
660const char* Top::kStackOverflowMessage =
661 "Uncaught RangeError: Maximum call stack size exceeded";
662
663
664Failure* Top::StackOverflow() {
665 HandleScope scope;
666 Handle<String> key = Factory::stack_overflow_symbol();
667 Handle<JSObject> boilerplate =
668 Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
669 Handle<Object> exception = Copy(boilerplate);
670 // TODO(1240995): To avoid having to call JavaScript code to compute
671 // the message for stack overflow exceptions which is very likely to
672 // double fault with another stack overflow exception, we use a
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100673 // precomputed message.
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 DoThrow(*exception, NULL, kStackOverflowMessage);
675 return Failure::Exception();
676}
677
678
679Failure* Top::TerminateExecution() {
680 DoThrow(Heap::termination_exception(), NULL, NULL);
681 return Failure::Exception();
682}
683
684
685Failure* Top::Throw(Object* exception, MessageLocation* location) {
686 DoThrow(exception, location, NULL);
687 return Failure::Exception();
688}
689
690
691Failure* Top::ReThrow(Object* exception, MessageLocation* location) {
692 // Set the exception being re-thrown.
693 set_pending_exception(exception);
694 return Failure::Exception();
695}
696
697
698Failure* Top::ThrowIllegalOperation() {
699 return Throw(Heap::illegal_access_symbol());
700}
701
702
703void Top::ScheduleThrow(Object* exception) {
704 // When scheduling a throw we first throw the exception to get the
705 // error reporting if it is uncaught before rescheduling it.
706 Throw(exception);
707 thread_local_.scheduled_exception_ = pending_exception();
708 thread_local_.external_caught_exception_ = false;
709 clear_pending_exception();
710}
711
712
713Object* Top::PromoteScheduledException() {
714 Object* thrown = scheduled_exception();
715 clear_scheduled_exception();
716 // Re-throw the exception to avoid getting repeated error reporting.
717 return ReThrow(thrown);
718}
719
720
721void Top::PrintCurrentStackTrace(FILE* out) {
722 StackTraceFrameIterator it;
723 while (!it.done()) {
724 HandleScope scope;
725 // Find code position if recorded in relocation info.
726 JavaScriptFrame* frame = it.frame();
727 int pos = frame->code()->SourcePosition(frame->pc());
728 Handle<Object> pos_obj(Smi::FromInt(pos));
729 // Fetch function and receiver.
730 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
731 Handle<Object> recv(frame->receiver());
732 // Advance to the next JavaScript frame and determine if the
733 // current frame is the top-level frame.
734 it.Advance();
735 Handle<Object> is_top_level = it.done()
736 ? Factory::true_value()
737 : Factory::false_value();
738 // Generate and print stack trace line.
739 Handle<String> line =
740 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
741 if (line->length() > 0) {
742 line->PrintOn(out);
743 fprintf(out, "\n");
744 }
745 }
746}
747
748
749void Top::ComputeLocation(MessageLocation* target) {
Andrei Popescu31002712010-02-23 13:46:05 +0000750 *target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 StackTraceFrameIterator it;
752 if (!it.done()) {
753 JavaScriptFrame* frame = it.frame();
754 JSFunction* fun = JSFunction::cast(frame->function());
755 Object* script = fun->shared()->script();
756 if (script->IsScript() &&
757 !(Script::cast(script)->source()->IsUndefined())) {
758 int pos = frame->code()->SourcePosition(frame->pc());
759 // Compute the location from the function and the reloc info.
760 Handle<Script> casted_script(Script::cast(script));
761 *target = MessageLocation(casted_script, pos, pos + 1);
762 }
763 }
764}
765
766
Steve Blocka7e24c12009-10-30 11:49:00 +0000767bool Top::ShouldReturnException(bool* is_caught_externally,
768 bool catchable_by_javascript) {
769 // Find the top-most try-catch handler.
770 StackHandler* handler =
771 StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
772 while (handler != NULL && !handler->is_try_catch()) {
773 handler = handler->next();
774 }
775
776 // Get the address of the external handler so we can compare the address to
777 // determine which one is closer to the top of the stack.
Steve Blockd0582a62009-12-15 09:54:21 +0000778 Address external_handler_address = thread_local_.try_catch_handler_address();
Steve Blocka7e24c12009-10-30 11:49:00 +0000779
780 // The exception has been externally caught if and only if there is
781 // an external handler which is on top of the top-most try-catch
782 // handler.
Steve Blockd0582a62009-12-15 09:54:21 +0000783 *is_caught_externally = external_handler_address != NULL &&
784 (handler == NULL || handler->address() > external_handler_address ||
Steve Blocka7e24c12009-10-30 11:49:00 +0000785 !catchable_by_javascript);
786
787 if (*is_caught_externally) {
788 // Only report the exception if the external handler is verbose.
Steve Blockd0582a62009-12-15 09:54:21 +0000789 return thread_local_.TryCatchHandler()->is_verbose_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000790 } else {
791 // Report the exception if it isn't caught by JavaScript code.
792 return handler == NULL;
793 }
794}
795
796
797void Top::DoThrow(Object* exception,
798 MessageLocation* location,
799 const char* message) {
800 ASSERT(!has_pending_exception());
801
802 HandleScope scope;
803 Handle<Object> exception_handle(exception);
804
805 // Determine reporting and whether the exception is caught externally.
806 bool is_caught_externally = false;
807 bool is_out_of_memory = exception == Failure::OutOfMemoryException();
808 bool is_termination_exception = exception == Heap::termination_exception();
809 bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory;
810 bool should_return_exception =
811 ShouldReturnException(&is_caught_externally, catchable_by_javascript);
812 bool report_exception = catchable_by_javascript && should_return_exception;
813
814#ifdef ENABLE_DEBUGGER_SUPPORT
815 // Notify debugger of exception.
816 if (catchable_by_javascript) {
817 Debugger::OnException(exception_handle, report_exception);
818 }
819#endif
820
821 // Generate the message.
822 Handle<Object> message_obj;
823 MessageLocation potential_computed_location;
824 bool try_catch_needs_message =
825 is_caught_externally &&
Steve Blockd0582a62009-12-15 09:54:21 +0000826 thread_local_.TryCatchHandler()->capture_message_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000827 if (report_exception || try_catch_needs_message) {
828 if (location == NULL) {
829 // If no location was specified we use a computed one instead
830 ComputeLocation(&potential_computed_location);
831 location = &potential_computed_location;
832 }
833 if (!Bootstrapper::IsActive()) {
834 // It's not safe to try to make message objects or collect stack
835 // traces while the bootstrapper is active since the infrastructure
836 // may not have been properly initialized.
837 Handle<String> stack_trace;
Kristian Monsen25f61362010-05-21 11:50:48 +0100838 if (FLAG_trace_exception) stack_trace = StackTraceString();
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100839 Handle<JSArray> stack_trace_object;
840 if (report_exception && capture_stack_trace_for_uncaught_exceptions) {
841 stack_trace_object = Top::CaptureCurrentStackTrace(
842 stack_trace_for_uncaught_exceptions_frame_limit,
843 stack_trace_for_uncaught_exceptions_options);
844 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000845 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100846 location, HandleVector<Object>(&exception_handle, 1), stack_trace,
847 stack_trace_object);
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 }
849 }
850
851 // Save the message for reporting if the the exception remains uncaught.
852 thread_local_.has_pending_message_ = report_exception;
853 thread_local_.pending_message_ = message;
854 if (!message_obj.is_null()) {
855 thread_local_.pending_message_obj_ = *message_obj;
856 if (location != NULL) {
857 thread_local_.pending_message_script_ = *location->script();
858 thread_local_.pending_message_start_pos_ = location->start_pos();
859 thread_local_.pending_message_end_pos_ = location->end_pos();
860 }
861 }
862
863 if (is_caught_externally) {
Steve Blockd0582a62009-12-15 09:54:21 +0000864 thread_local_.catcher_ = thread_local_.TryCatchHandler();
Steve Blocka7e24c12009-10-30 11:49:00 +0000865 }
866
867 // NOTE: Notifying the debugger or generating the message
868 // may have caused new exceptions. For now, we just ignore
869 // that and set the pending exception to the original one.
870 set_pending_exception(*exception_handle);
871}
872
873
874void Top::ReportPendingMessages() {
875 ASSERT(has_pending_exception());
876 setup_external_caught();
877 // If the pending exception is OutOfMemoryException set out_of_memory in
878 // the global context. Note: We have to mark the global context here
879 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
880 // set it.
881 bool external_caught = thread_local_.external_caught_exception_;
882 HandleScope scope;
883 if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
884 context()->mark_out_of_memory();
885 } else if (thread_local_.pending_exception_ ==
886 Heap::termination_exception()) {
887 if (external_caught) {
Steve Blockd0582a62009-12-15 09:54:21 +0000888 thread_local_.TryCatchHandler()->can_continue_ = false;
889 thread_local_.TryCatchHandler()->exception_ = Heap::null_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000890 }
891 } else {
892 Handle<Object> exception(pending_exception());
893 thread_local_.external_caught_exception_ = false;
894 if (external_caught) {
Steve Blockd0582a62009-12-15 09:54:21 +0000895 thread_local_.TryCatchHandler()->can_continue_ = true;
896 thread_local_.TryCatchHandler()->exception_ =
Steve Blocka7e24c12009-10-30 11:49:00 +0000897 thread_local_.pending_exception_;
898 if (!thread_local_.pending_message_obj_->IsTheHole()) {
899 try_catch_handler()->message_ = thread_local_.pending_message_obj_;
900 }
901 }
902 if (thread_local_.has_pending_message_) {
903 thread_local_.has_pending_message_ = false;
904 if (thread_local_.pending_message_ != NULL) {
905 MessageHandler::ReportMessage(thread_local_.pending_message_);
906 } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
907 Handle<Object> message_obj(thread_local_.pending_message_obj_);
908 if (thread_local_.pending_message_script_ != NULL) {
909 Handle<Script> script(thread_local_.pending_message_script_);
910 int start_pos = thread_local_.pending_message_start_pos_;
911 int end_pos = thread_local_.pending_message_end_pos_;
912 MessageLocation location(script, start_pos, end_pos);
913 MessageHandler::ReportMessage(&location, message_obj);
914 } else {
915 MessageHandler::ReportMessage(NULL, message_obj);
916 }
917 }
918 }
919 thread_local_.external_caught_exception_ = external_caught;
920 set_pending_exception(*exception);
921 }
922 clear_pending_message();
923}
924
925
926void Top::TraceException(bool flag) {
927 FLAG_trace_exception = flag;
928}
929
930
931bool Top::OptionalRescheduleException(bool is_bottom_call) {
932 // Allways reschedule out of memory exceptions.
933 if (!is_out_of_memory()) {
934 bool is_termination_exception =
935 pending_exception() == Heap::termination_exception();
936
937 // Do not reschedule the exception if this is the bottom call.
938 bool clear_exception = is_bottom_call;
939
940 if (is_termination_exception) {
941 if (is_bottom_call) {
942 thread_local_.external_caught_exception_ = false;
943 clear_pending_exception();
944 return false;
945 }
946 } else if (thread_local_.external_caught_exception_) {
947 // If the exception is externally caught, clear it if there are no
948 // JavaScript frames on the way to the C++ frame that has the
949 // external handler.
Steve Blockd0582a62009-12-15 09:54:21 +0000950 ASSERT(thread_local_.try_catch_handler_address() != NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 Address external_handler_address =
Steve Blockd0582a62009-12-15 09:54:21 +0000952 thread_local_.try_catch_handler_address();
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 JavaScriptFrameIterator it;
954 if (it.done() || (it.frame()->sp() > external_handler_address)) {
955 clear_exception = true;
956 }
957 }
958
959 // Clear the exception if needed.
960 if (clear_exception) {
961 thread_local_.external_caught_exception_ = false;
962 clear_pending_exception();
963 return false;
964 }
965 }
966
967 // Reschedule the exception.
968 thread_local_.scheduled_exception_ = pending_exception();
969 clear_pending_exception();
970 return true;
971}
972
973
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100974void Top::SetCaptureStackTraceForUncaughtExceptions(
975 bool capture,
976 int frame_limit,
977 StackTrace::StackTraceOptions options) {
978 capture_stack_trace_for_uncaught_exceptions = capture;
979 stack_trace_for_uncaught_exceptions_frame_limit = frame_limit;
980 stack_trace_for_uncaught_exceptions_options = options;
981}
982
983
Steve Blocka7e24c12009-10-30 11:49:00 +0000984bool Top::is_out_of_memory() {
985 if (has_pending_exception()) {
986 Object* e = pending_exception();
987 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
988 return true;
989 }
990 }
991 if (has_scheduled_exception()) {
992 Object* e = scheduled_exception();
993 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
994 return true;
995 }
996 }
997 return false;
998}
999
1000
1001Handle<Context> Top::global_context() {
1002 GlobalObject* global = thread_local_.context_->global();
1003 return Handle<Context>(global->global_context());
1004}
1005
1006
1007Handle<Context> Top::GetCallingGlobalContext() {
1008 JavaScriptFrameIterator it;
Steve Blockd0582a62009-12-15 09:54:21 +00001009#ifdef ENABLE_DEBUGGER_SUPPORT
1010 if (Debug::InDebugger()) {
1011 while (!it.done()) {
1012 JavaScriptFrame* frame = it.frame();
1013 Context* context = Context::cast(frame->context());
1014 if (context->global_context() == *Debug::debug_context()) {
1015 it.Advance();
1016 } else {
1017 break;
1018 }
1019 }
1020 }
1021#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +00001022 if (it.done()) return Handle<Context>::null();
1023 JavaScriptFrame* frame = it.frame();
1024 Context* context = Context::cast(frame->context());
1025 return Handle<Context>(context->global_context());
1026}
1027
1028
Steve Blocka7e24c12009-10-30 11:49:00 +00001029char* Top::ArchiveThread(char* to) {
1030 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
1031 InitializeThreadLocal();
1032 return to + sizeof(thread_local_);
1033}
1034
1035
1036char* Top::RestoreThread(char* from) {
1037 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
1038 return from + sizeof(thread_local_);
1039}
1040
1041
1042ExecutionAccess::ExecutionAccess() {
1043 Top::break_access_->Lock();
1044}
1045
1046
1047ExecutionAccess::~ExecutionAccess() {
1048 Top::break_access_->Unlock();
1049}
1050
1051
1052} } // namespace v8::internal