blob: e32eb6bc8b2677b64db262582b9c48c112d4033b [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000034#include "messages.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "platform.h"
ager@chromium.orgc4c92722009-11-18 14:12:51 +000036#include "simulator.h"
37#include "string-stream.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039
kasperl@chromium.org71affb52009-05-26 05:44:31 +000040namespace v8 {
41namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000043#ifdef ENABLE_LOGGING_AND_PROFILING
kasperl@chromium.orga5551262010-12-07 12:49:48 +000044Semaphore* Top::runtime_profiler_semaphore_ = NULL;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000045#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046ThreadLocalTop Top::thread_local_;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000047Mutex* Top::break_access_ = OS::CreateMutex();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000048
kasper.lundaf4734f2008-07-28 12:50:18 +000049NoAllocationStringAllocator* preallocated_message_space = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000051bool capture_stack_trace_for_uncaught_exceptions = false;
52int stack_trace_for_uncaught_exceptions_frame_limit = 0;
53StackTrace::StackTraceOptions stack_trace_for_uncaught_exceptions_options =
54 StackTrace::kOverview;
55
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000056Address top_addresses[] = {
57#define C(name) reinterpret_cast<Address>(Top::name()),
58 TOP_ADDRESS_LIST(C)
ager@chromium.orge2902be2009-06-08 12:21:35 +000059 TOP_ADDRESS_LIST_PROF(C)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000060#undef C
61 NULL
62};
63
ager@chromium.orgc4c92722009-11-18 14:12:51 +000064
65v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
66 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
67}
68
69
70void ThreadLocalTop::Initialize() {
71 c_entry_fp_ = 0;
72 handler_ = 0;
lrn@chromium.org303ada72010-10-27 09:33:13 +000073#ifdef USE_SIMULATOR
74#ifdef V8_TARGET_ARCH_ARM
ager@chromium.org378b34e2011-01-28 08:04:38 +000075 simulator_ = Simulator::current();
lrn@chromium.org303ada72010-10-27 09:33:13 +000076#elif V8_TARGET_ARCH_MIPS
77 simulator_ = assembler::mips::Simulator::current();
78#endif
79#endif
ager@chromium.orgc4c92722009-11-18 14:12:51 +000080#ifdef ENABLE_LOGGING_AND_PROFILING
kasperl@chromium.orga5551262010-12-07 12:49:48 +000081 js_entry_sp_ = NULL;
82 external_callback_ = NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000083#endif
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000084#ifdef ENABLE_VMSTATE_TRACKING
kasperl@chromium.orga5551262010-12-07 12:49:48 +000085 current_vm_state_ = EXTERNAL;
86 runtime_profiler_state_ = Top::PROF_NOT_IN_JS;
whesse@chromium.org4a5224e2010-10-20 12:37:07 +000087#endif
ager@chromium.orgc4c92722009-11-18 14:12:51 +000088 try_catch_handler_address_ = NULL;
89 context_ = NULL;
90 int id = ThreadManager::CurrentId();
91 thread_id_ = (id == 0) ? ThreadManager::kInvalidId : id;
92 external_caught_exception_ = false;
93 failed_access_check_callback_ = NULL;
94 save_context_ = NULL;
95 catcher_ = NULL;
96}
97
98
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000099Address Top::get_address_from_id(Top::AddressId id) {
100 return top_addresses[id];
101}
102
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000104char* Top::Iterate(ObjectVisitor* v, char* thread_storage) {
105 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
106 Iterate(v, thread);
107 return thread_storage + sizeof(ThreadLocalTop);
108}
109
110
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000111void Top::IterateThread(ThreadVisitor* v) {
112 v->VisitThread(&thread_local_);
113}
114
115
116void Top::IterateThread(ThreadVisitor* v, char* t) {
117 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
118 v->VisitThread(thread);
119}
120
121
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122void Top::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000123 // Visit the roots from the top for a given thread.
124 Object *pending;
125 // The pending exception can sometimes be a failure. We can't show
126 // that to the GC, which only understands objects.
127 if (thread->pending_exception_->ToObject(&pending)) {
128 v->VisitPointer(&pending);
129 thread->pending_exception_ = pending; // In case GC updated it.
130 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000131 v->VisitPointer(&(thread->pending_message_obj_));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000132 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_)));
133 v->VisitPointer(BitCast<Object**>(&(thread->context_)));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000134 Object* scheduled;
135 if (thread->scheduled_exception_->ToObject(&scheduled)) {
136 v->VisitPointer(&scheduled);
137 thread->scheduled_exception_ = scheduled;
138 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000140 for (v8::TryCatch* block = thread->TryCatchHandler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 block != NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000142 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000143 v->VisitPointer(BitCast<Object**>(&(block->exception_)));
144 v->VisitPointer(BitCast<Object**>(&(block->message_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000145 }
146
147 // Iterate over pointers on native execution stack.
148 for (StackFrameIterator it(thread); !it.done(); it.Advance()) {
149 it.frame()->Iterate(v);
150 }
151}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000152
153
154void Top::Iterate(ObjectVisitor* v) {
155 ThreadLocalTop* current_t = &thread_local_;
156 Iterate(v, current_t);
157}
158
159
160void Top::InitializeThreadLocal() {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000161 thread_local_.Initialize();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000162 clear_pending_exception();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000163 clear_pending_message();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000164 clear_scheduled_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000165}
166
167
kasper.lundaf4734f2008-07-28 12:50:18 +0000168// Create a dummy thread that will wait forever on a semaphore. The only
169// purpose for this thread is to have some stack area to save essential data
170// into for use by a stacks only core dump (aka minidump).
171class PreallocatedMemoryThread: public Thread {
172 public:
lrn@chromium.org5d00b602011-01-05 09:51:43 +0000173 PreallocatedMemoryThread()
174 : Thread("v8:PreallocMem"),
175 keep_running_(true) {
kasper.lundaf4734f2008-07-28 12:50:18 +0000176 wait_for_ever_semaphore_ = OS::CreateSemaphore(0);
177 data_ready_semaphore_ = OS::CreateSemaphore(0);
178 }
179
180 // When the thread starts running it will allocate a fixed number of bytes
181 // on the stack and publish the location of this memory for others to use.
182 void Run() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000183 EmbeddedVector<char, 15 * 1024> local_buffer;
kasper.lundaf4734f2008-07-28 12:50:18 +0000184
185 // Initialize the buffer with a known good value.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000186 OS::StrNCpy(local_buffer, "Trace data was not generated.\n",
187 local_buffer.length());
kasper.lundaf4734f2008-07-28 12:50:18 +0000188
189 // Publish the local buffer and signal its availability.
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000190 data_ = local_buffer.start();
191 length_ = local_buffer.length();
kasper.lundaf4734f2008-07-28 12:50:18 +0000192 data_ready_semaphore_->Signal();
193
194 while (keep_running_) {
195 // This thread will wait here until the end of time.
196 wait_for_ever_semaphore_->Wait();
197 }
198
199 // Make sure we access the buffer after the wait to remove all possibility
200 // of it being optimized away.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000201 OS::StrNCpy(local_buffer, "PreallocatedMemoryThread shutting down.\n",
202 local_buffer.length());
kasper.lundaf4734f2008-07-28 12:50:18 +0000203 }
204
205 static char* data() {
206 if (data_ready_semaphore_ != NULL) {
207 // Initial access is guarded until the data has been published.
208 data_ready_semaphore_->Wait();
209 delete data_ready_semaphore_;
210 data_ready_semaphore_ = NULL;
211 }
212 return data_;
213 }
214
215 static unsigned length() {
216 if (data_ready_semaphore_ != NULL) {
217 // Initial access is guarded until the data has been published.
218 data_ready_semaphore_->Wait();
219 delete data_ready_semaphore_;
220 data_ready_semaphore_ = NULL;
221 }
222 return length_;
223 }
224
225 static void StartThread() {
226 if (the_thread_ != NULL) return;
227
228 the_thread_ = new PreallocatedMemoryThread();
229 the_thread_->Start();
230 }
231
232 // Stop the PreallocatedMemoryThread and release its resources.
233 static void StopThread() {
234 if (the_thread_ == NULL) return;
235
236 the_thread_->keep_running_ = false;
237 wait_for_ever_semaphore_->Signal();
238
239 // Wait for the thread to terminate.
240 the_thread_->Join();
241
242 if (data_ready_semaphore_ != NULL) {
243 delete data_ready_semaphore_;
244 data_ready_semaphore_ = NULL;
245 }
246
247 delete wait_for_ever_semaphore_;
248 wait_for_ever_semaphore_ = NULL;
249
250 // Done with the thread entirely.
251 delete the_thread_;
252 the_thread_ = NULL;
253 }
254
255 private:
256 // Used to make sure that the thread keeps looping even for spurious wakeups.
257 bool keep_running_;
258
259 // The preallocated memory thread singleton.
260 static PreallocatedMemoryThread* the_thread_;
261 // This semaphore is used by the PreallocatedMemoryThread to wait for ever.
262 static Semaphore* wait_for_ever_semaphore_;
263 // Semaphore to signal that the data has been initialized.
264 static Semaphore* data_ready_semaphore_;
265
266 // Location and size of the preallocated memory block.
267 static char* data_;
268 static unsigned length_;
269
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000270 DISALLOW_COPY_AND_ASSIGN(PreallocatedMemoryThread);
kasper.lundaf4734f2008-07-28 12:50:18 +0000271};
272
273PreallocatedMemoryThread* PreallocatedMemoryThread::the_thread_ = NULL;
274Semaphore* PreallocatedMemoryThread::wait_for_ever_semaphore_ = NULL;
275Semaphore* PreallocatedMemoryThread::data_ready_semaphore_ = NULL;
276char* PreallocatedMemoryThread::data_ = NULL;
277unsigned PreallocatedMemoryThread::length_ = 0;
278
279static bool initialized = false;
280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281void Top::Initialize() {
kasper.lundaf4734f2008-07-28 12:50:18 +0000282 CHECK(!initialized);
283
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000284#ifdef ENABLE_LOGGING_AND_PROFILING
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000285 ASSERT(runtime_profiler_semaphore_ == NULL);
286 runtime_profiler_semaphore_ = OS::CreateSemaphore(0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000287#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000288
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000289 InitializeThreadLocal();
290
kasper.lundaf4734f2008-07-28 12:50:18 +0000291 // Only preallocate on the first initialization.
292 if (FLAG_preallocate_message_memory && (preallocated_message_space == NULL)) {
293 // Start the thread which will set aside some memory.
294 PreallocatedMemoryThread::StartThread();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 preallocated_message_space =
kasper.lundaf4734f2008-07-28 12:50:18 +0000296 new NoAllocationStringAllocator(PreallocatedMemoryThread::data(),
297 PreallocatedMemoryThread::length());
298 PreallocatedStorage::Init(PreallocatedMemoryThread::length() / 4);
299 }
300 initialized = true;
301}
302
303
304void Top::TearDown() {
305 if (initialized) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000306#ifdef ENABLE_LOGGING_AND_PROFILING
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000307 delete runtime_profiler_semaphore_;
308 runtime_profiler_semaphore_ = NULL;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000309#endif
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000310
kasper.lundaf4734f2008-07-28 12:50:18 +0000311 // Remove the external reference to the preallocated stack memory.
312 if (preallocated_message_space != NULL) {
313 delete preallocated_message_space;
314 preallocated_message_space = NULL;
315 }
316
317 PreallocatedMemoryThread::StopThread();
318 initialized = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 }
320}
321
322
323void Top::RegisterTryCatchHandler(v8::TryCatch* that) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000324 // The ARM simulator has a separate JS stack. We therefore register
325 // the C++ try catch handler with the simulator and get back an
326 // address that can be used for comparisons with addresses into the
327 // JS stack. When running without the simulator, the address
328 // returned will be the address of the C++ try catch handler itself.
329 Address address = reinterpret_cast<Address>(
330 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
331 thread_local_.set_try_catch_handler_address(address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332}
333
334
335void Top::UnregisterTryCatchHandler(v8::TryCatch* that) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000336 ASSERT(thread_local_.TryCatchHandler() == that);
337 thread_local_.set_try_catch_handler_address(
338 reinterpret_cast<Address>(that->next_));
ager@chromium.org71daaf62009-04-01 07:22:49 +0000339 thread_local_.catcher_ = NULL;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000340 SimulatorStack::UnregisterCTryCatch();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000341}
342
343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344
345static int stack_trace_nesting_level = 0;
346static StringStream* incomplete_message = NULL;
347
348
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000349Handle<String> Top::StackTraceString() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000350 if (stack_trace_nesting_level == 0) {
351 stack_trace_nesting_level++;
352 HeapStringAllocator allocator;
353 StringStream::ClearMentionedObjectCache();
354 StringStream accumulator(&allocator);
355 incomplete_message = &accumulator;
356 PrintStack(&accumulator);
357 Handle<String> stack_trace = accumulator.ToString();
358 incomplete_message = NULL;
359 stack_trace_nesting_level = 0;
360 return stack_trace;
361 } else if (stack_trace_nesting_level == 1) {
362 stack_trace_nesting_level++;
363 OS::PrintError(
364 "\n\nAttempt to print stack while printing stack (double fault)\n");
365 OS::PrintError(
366 "If you are lucky you may find a partial stack dump on stdout.\n\n");
367 incomplete_message->OutputToStdOut();
368 return Factory::empty_symbol();
369 } else {
370 OS::Abort();
371 // Unreachable
372 return Factory::empty_symbol();
373 }
374}
375
376
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000377Handle<JSArray> Top::CaptureCurrentStackTrace(
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000378 int frame_limit, StackTrace::StackTraceOptions options) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000379 // Ensure no negative values.
380 int limit = Max(frame_limit, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000381 Handle<JSArray> stack_trace = Factory::NewJSArray(frame_limit);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000382
383 Handle<String> column_key = Factory::LookupAsciiSymbol("column");
384 Handle<String> line_key = Factory::LookupAsciiSymbol("lineNumber");
385 Handle<String> script_key = Factory::LookupAsciiSymbol("scriptName");
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000386 Handle<String> name_or_source_url_key =
387 Factory::LookupAsciiSymbol("nameOrSourceURL");
388 Handle<String> script_name_or_source_url_key =
389 Factory::LookupAsciiSymbol("scriptNameOrSourceURL");
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000390 Handle<String> function_key = Factory::LookupAsciiSymbol("functionName");
391 Handle<String> eval_key = Factory::LookupAsciiSymbol("isEval");
392 Handle<String> constructor_key = Factory::LookupAsciiSymbol("isConstructor");
393
394 StackTraceFrameIterator it;
395 int frames_seen = 0;
396 while (!it.done() && (frames_seen < limit)) {
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000397 JavaScriptFrame* frame = it.frame();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000398
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000399 List<FrameSummary> frames(3); // Max 2 levels of inlining.
400 frame->Summarize(&frames);
401 for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
402 // Create a JSObject to hold the information for the StackFrame.
403 Handle<JSObject> stackFrame = Factory::NewJSObject(object_function());
404
405 Handle<JSFunction> fun = frames[i].function();
406 Handle<Script> script(Script::cast(fun->shared()->script()));
407
408 if (options & StackTrace::kLineNumber) {
409 int script_line_offset = script->line_offset()->value();
410 int position = frames[i].code()->SourcePosition(frames[i].pc());
411 int line_number = GetScriptLineNumber(script, position);
412 // line_number is already shifted by the script_line_offset.
413 int relative_line_number = line_number - script_line_offset;
414 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
415 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
416 int start = (relative_line_number == 0) ? 0 :
417 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
418 int column_offset = position - start;
419 if (relative_line_number == 0) {
420 // For the case where the code is on the same line as the script
421 // tag.
422 column_offset += script->column_offset()->value();
423 }
424 SetProperty(stackFrame, column_key,
425 Handle<Smi>(Smi::FromInt(column_offset + 1)), NONE);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000426 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000427 SetProperty(stackFrame, line_key,
428 Handle<Smi>(Smi::FromInt(line_number + 1)), NONE);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000429 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000430
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000431 if (options & StackTrace::kScriptName) {
432 Handle<Object> script_name(script->name());
433 SetProperty(stackFrame, script_key, script_name, NONE);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000434 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000435
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000436 if (options & StackTrace::kScriptNameOrSourceURL) {
437 Handle<Object> script_name(script->name());
438 Handle<JSValue> script_wrapper = GetScriptWrapper(script);
439 Handle<Object> property = GetProperty(script_wrapper,
440 name_or_source_url_key);
441 ASSERT(property->IsJSFunction());
442 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
443 bool caught_exception;
444 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
445 NULL, &caught_exception);
446 if (caught_exception) {
447 result = Factory::undefined_value();
448 }
449 SetProperty(stackFrame, script_name_or_source_url_key, result, NONE);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000450 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000451
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000452 if (options & StackTrace::kFunctionName) {
453 Handle<Object> fun_name(fun->shared()->name());
454 if (fun_name->ToBoolean()->IsFalse()) {
455 fun_name = Handle<Object>(fun->shared()->inferred_name());
456 }
457 SetProperty(stackFrame, function_key, fun_name, NONE);
458 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000459
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000460 if (options & StackTrace::kIsEval) {
461 int type = Smi::cast(script->compilation_type())->value();
462 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
463 Factory::true_value() : Factory::false_value();
464 SetProperty(stackFrame, eval_key, is_eval, NONE);
465 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000466
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000467 if (options & StackTrace::kIsConstructor) {
468 Handle<Object> is_constructor = (frames[i].is_constructor()) ?
469 Factory::true_value() : Factory::false_value();
470 SetProperty(stackFrame, constructor_key, is_constructor, NONE);
471 }
472
473 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame);
474 frames_seen++;
475 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000476 it.Advance();
477 }
478
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000479 stack_trace->set_length(Smi::FromInt(frames_seen));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000480 return stack_trace;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000481}
482
483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484void Top::PrintStack() {
485 if (stack_trace_nesting_level == 0) {
486 stack_trace_nesting_level++;
487
488 StringAllocator* allocator;
kasper.lundaf4734f2008-07-28 12:50:18 +0000489 if (preallocated_message_space == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490 allocator = new HeapStringAllocator();
491 } else {
492 allocator = preallocated_message_space;
493 }
494
495 NativeAllocationChecker allocation_checker(
kasper.lundaf4734f2008-07-28 12:50:18 +0000496 !FLAG_preallocate_message_memory ?
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 NativeAllocationChecker::ALLOW :
498 NativeAllocationChecker::DISALLOW);
499
500 StringStream::ClearMentionedObjectCache();
501 StringStream accumulator(allocator);
502 incomplete_message = &accumulator;
503 PrintStack(&accumulator);
504 accumulator.OutputToStdOut();
505 accumulator.Log();
506 incomplete_message = NULL;
507 stack_trace_nesting_level = 0;
kasper.lundaf4734f2008-07-28 12:50:18 +0000508 if (preallocated_message_space == NULL) {
509 // Remove the HeapStringAllocator created above.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000510 delete allocator;
511 }
512 } else if (stack_trace_nesting_level == 1) {
513 stack_trace_nesting_level++;
514 OS::PrintError(
515 "\n\nAttempt to print stack while printing stack (double fault)\n");
516 OS::PrintError(
517 "If you are lucky you may find a partial stack dump on stdout.\n\n");
518 incomplete_message->OutputToStdOut();
519 }
520}
521
522
523static void PrintFrames(StringStream* accumulator,
524 StackFrame::PrintMode mode) {
525 StackFrameIterator it;
526 for (int i = 0; !it.done(); it.Advance()) {
527 it.frame()->Print(accumulator, mode, i++);
528 }
529}
530
531
532void Top::PrintStack(StringStream* accumulator) {
533 // The MentionedObjectCache is not GC-proof at the moment.
534 AssertNoAllocation nogc;
535 ASSERT(StringStream::IsMentionedObjectCacheClear());
536
537 // Avoid printing anything if there are no frames.
538 if (c_entry_fp(GetCurrentThread()) == 0) return;
539
540 accumulator->Add(
541 "\n==== Stack trace ============================================\n\n");
542 PrintFrames(accumulator, StackFrame::OVERVIEW);
543
544 accumulator->Add(
545 "\n==== Details ================================================\n\n");
546 PrintFrames(accumulator, StackFrame::DETAILS);
547
548 accumulator->PrintMentionedObjectCache();
549 accumulator->Add("=====================\n\n");
550}
551
552
553void Top::SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000554 thread_local_.failed_access_check_callback_ = callback;
555}
556
557
558void Top::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
559 if (!thread_local_.failed_access_check_callback_) return;
560
561 ASSERT(receiver->IsAccessCheckNeeded());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000562 ASSERT(Top::context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563
564 // Get the data object from access check info.
565 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000566 if (!constructor->shared()->IsApiFunction()) return;
567 Object* data_obj =
568 constructor->shared()->get_api_func_data()->access_check_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569 if (data_obj == Heap::undefined_value()) return;
570
571 HandleScope scope;
572 Handle<JSObject> receiver_handle(receiver);
573 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
574 thread_local_.failed_access_check_callback_(
575 v8::Utils::ToLocal(receiver_handle),
576 type,
577 v8::Utils::ToLocal(data));
578}
579
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000580
581enum MayAccessDecision {
582 YES, NO, UNKNOWN
583};
584
585
586static MayAccessDecision MayAccessPreCheck(JSObject* receiver,
587 v8::AccessType type) {
588 // During bootstrapping, callback functions are not enabled yet.
589 if (Bootstrapper::IsActive()) return YES;
590
591 if (receiver->IsJSGlobalProxy()) {
592 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
593 if (!receiver_context->IsContext()) return NO;
594
595 // Get the global context of current top context.
596 // avoid using Top::global_context() because it uses Handle.
597 Context* global_context = Top::context()->global()->global_context();
598 if (receiver_context == global_context) return YES;
599
600 if (Context::cast(receiver_context)->security_token() ==
601 global_context->security_token())
602 return YES;
603 }
604
605 return UNKNOWN;
606}
607
608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000609bool Top::MayNamedAccess(JSObject* receiver, Object* key, v8::AccessType type) {
610 ASSERT(receiver->IsAccessCheckNeeded());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000611
612 // The callers of this method are not expecting a GC.
613 AssertNoAllocation no_gc;
614
615 // Skip checks for hidden properties access. Note, we do not
616 // require existence of a context in this case.
617 if (key == Heap::hidden_symbol()) return true;
618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 // Check for compatibility between the security tokens in the
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000620 // current lexical context and the accessed object.
621 ASSERT(Top::context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000623 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
624 if (decision != UNKNOWN) return decision == YES;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625
626 // Get named access check callback
627 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000628 if (!constructor->shared()->IsApiFunction()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000629
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000630 Object* data_obj =
631 constructor->shared()->get_api_func_data()->access_check_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632 if (data_obj == Heap::undefined_value()) return false;
633
634 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
635 v8::NamedSecurityCallback callback =
636 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
637
638 if (!callback) return false;
639
640 HandleScope scope;
641 Handle<JSObject> receiver_handle(receiver);
642 Handle<Object> key_handle(key);
643 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
644 LOG(ApiNamedSecurityCheck(key));
645 bool result = false;
646 {
647 // Leaving JavaScript.
ager@chromium.org41826e72009-03-30 13:30:57 +0000648 VMState state(EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 result = callback(v8::Utils::ToLocal(receiver_handle),
650 v8::Utils::ToLocal(key_handle),
651 type,
652 v8::Utils::ToLocal(data));
653 }
654 return result;
655}
656
657
658bool Top::MayIndexedAccess(JSObject* receiver,
659 uint32_t index,
660 v8::AccessType type) {
661 ASSERT(receiver->IsAccessCheckNeeded());
662 // Check for compatibility between the security tokens in the
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000663 // current lexical context and the accessed object.
664 ASSERT(Top::context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000665 // The callers of this method are not expecting a GC.
666 AssertNoAllocation no_gc;
667
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000668 MayAccessDecision decision = MayAccessPreCheck(receiver, type);
669 if (decision != UNKNOWN) return decision == YES;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670
671 // Get indexed access check callback
672 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000673 if (!constructor->shared()->IsApiFunction()) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000674
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000675 Object* data_obj =
676 constructor->shared()->get_api_func_data()->access_check_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677 if (data_obj == Heap::undefined_value()) return false;
678
679 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
680 v8::IndexedSecurityCallback callback =
681 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
682
683 if (!callback) return false;
684
685 HandleScope scope;
686 Handle<JSObject> receiver_handle(receiver);
687 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
688 LOG(ApiIndexedSecurityCheck(index));
689 bool result = false;
690 {
691 // Leaving JavaScript.
ager@chromium.org41826e72009-03-30 13:30:57 +0000692 VMState state(EXTERNAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693 result = callback(v8::Utils::ToLocal(receiver_handle),
694 index,
695 type,
696 v8::Utils::ToLocal(data));
697 }
698 return result;
699}
700
701
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000702const char* Top::kStackOverflowMessage =
703 "Uncaught RangeError: Maximum call stack size exceeded";
704
705
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706Failure* Top::StackOverflow() {
707 HandleScope scope;
708 Handle<String> key = Factory::stack_overflow_symbol();
709 Handle<JSObject> boilerplate =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000710 Handle<JSObject>::cast(GetProperty(Top::builtins(), key));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711 Handle<Object> exception = Copy(boilerplate);
712 // TODO(1240995): To avoid having to call JavaScript code to compute
713 // the message for stack overflow exceptions which is very likely to
714 // double fault with another stack overflow exception, we use a
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000715 // precomputed message.
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000716 DoThrow(*exception, NULL, kStackOverflowMessage);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717 return Failure::Exception();
718}
719
720
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000721Failure* Top::TerminateExecution() {
722 DoThrow(Heap::termination_exception(), NULL, NULL);
723 return Failure::Exception();
724}
725
726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000727Failure* Top::Throw(Object* exception, MessageLocation* location) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000728 DoThrow(exception, location, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729 return Failure::Exception();
730}
731
732
lrn@chromium.org303ada72010-10-27 09:33:13 +0000733Failure* Top::ReThrow(MaybeObject* exception, MessageLocation* location) {
ager@chromium.org32912102009-01-16 10:38:43 +0000734 // Set the exception being re-thrown.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000735 set_pending_exception(exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736 return Failure::Exception();
737}
738
739
ager@chromium.org3e875802009-06-29 08:26:34 +0000740Failure* Top::ThrowIllegalOperation() {
741 return Throw(Heap::illegal_access_symbol());
742}
743
744
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745void Top::ScheduleThrow(Object* exception) {
746 // When scheduling a throw we first throw the exception to get the
747 // error reporting if it is uncaught before rescheduling it.
748 Throw(exception);
749 thread_local_.scheduled_exception_ = pending_exception();
750 thread_local_.external_caught_exception_ = false;
751 clear_pending_exception();
752}
753
754
lrn@chromium.org303ada72010-10-27 09:33:13 +0000755Failure* Top::PromoteScheduledException() {
756 MaybeObject* thrown = scheduled_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000757 clear_scheduled_exception();
758 // Re-throw the exception to avoid getting repeated error reporting.
759 return ReThrow(thrown);
760}
761
762
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763void Top::PrintCurrentStackTrace(FILE* out) {
764 StackTraceFrameIterator it;
765 while (!it.done()) {
766 HandleScope scope;
767 // Find code position if recorded in relocation info.
768 JavaScriptFrame* frame = it.frame();
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000769 int pos = frame->code()->SourcePosition(frame->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000770 Handle<Object> pos_obj(Smi::FromInt(pos));
771 // Fetch function and receiver.
772 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
773 Handle<Object> recv(frame->receiver());
774 // Advance to the next JavaScript frame and determine if the
775 // current frame is the top-level frame.
776 it.Advance();
777 Handle<Object> is_top_level = it.done()
778 ? Factory::true_value()
779 : Factory::false_value();
ager@chromium.org32912102009-01-16 10:38:43 +0000780 // Generate and print stack trace line.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000781 Handle<String> line =
782 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
783 if (line->length() > 0) {
784 line->PrintOn(out);
785 fprintf(out, "\n");
786 }
787 }
788}
789
790
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000791void Top::ComputeLocation(MessageLocation* target) {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000792 *target = MessageLocation(Handle<Script>(Heap::empty_script()), -1, -1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000793 StackTraceFrameIterator it;
794 if (!it.done()) {
795 JavaScriptFrame* frame = it.frame();
796 JSFunction* fun = JSFunction::cast(frame->function());
797 Object* script = fun->shared()->script();
798 if (script->IsScript() &&
799 !(Script::cast(script)->source()->IsUndefined())) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000800 int pos = frame->code()->SourcePosition(frame->pc());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000801 // Compute the location from the function and the reloc info.
802 Handle<Script> casted_script(Script::cast(script));
803 *target = MessageLocation(casted_script, pos, pos + 1);
804 }
805 }
806}
807
808
ager@chromium.org378b34e2011-01-28 08:04:38 +0000809bool Top::ShouldReportException(bool* is_caught_externally,
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000810 bool catchable_by_javascript) {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000811 // Find the top-most try-catch handler.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 StackHandler* handler =
813 StackHandler::FromAddress(Top::handler(Top::GetCurrentThread()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 while (handler != NULL && !handler->is_try_catch()) {
815 handler = handler->next();
816 }
817
ager@chromium.org8bb60582008-12-11 12:02:20 +0000818 // Get the address of the external handler so we can compare the address to
819 // determine which one is closer to the top of the stack.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000820 Address external_handler_address = thread_local_.try_catch_handler_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000821
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000822 // The exception has been externally caught if and only if there is
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000823 // an external handler which is on top of the top-most try-catch
824 // handler.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000825 *is_caught_externally = external_handler_address != NULL &&
826 (handler == NULL || handler->address() > external_handler_address ||
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000827 !catchable_by_javascript);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000828
ager@chromium.org8bb60582008-12-11 12:02:20 +0000829 if (*is_caught_externally) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000830 // Only report the exception if the external handler is verbose.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000831 return thread_local_.TryCatchHandler()->is_verbose_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 } else {
833 // Report the exception if it isn't caught by JavaScript code.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000834 return handler == NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835 }
836}
837
838
lrn@chromium.org303ada72010-10-27 09:33:13 +0000839void Top::DoThrow(MaybeObject* exception,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000840 MessageLocation* location,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000841 const char* message) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 ASSERT(!has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000843
844 HandleScope scope;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000845 Object* exception_object = Smi::FromInt(0);
846 bool is_object = exception->ToObject(&exception_object);
847 Handle<Object> exception_handle(exception_object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000848
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000849 // Determine reporting and whether the exception is caught externally.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000850 bool is_out_of_memory = exception == Failure::OutOfMemoryException();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000851 bool is_termination_exception = exception == Heap::termination_exception();
852 bool catchable_by_javascript = !is_termination_exception && !is_out_of_memory;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000853 // Only real objects can be caught by JS.
854 ASSERT(!catchable_by_javascript || is_object);
ager@chromium.org378b34e2011-01-28 08:04:38 +0000855 bool is_caught_externally = false;
856 bool should_report_exception =
857 ShouldReportException(&is_caught_externally, catchable_by_javascript);
858 bool report_exception = catchable_by_javascript && should_report_exception;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000859
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000860#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org8bb60582008-12-11 12:02:20 +0000861 // Notify debugger of exception.
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000862 if (catchable_by_javascript) {
863 Debugger::OnException(exception_handle, report_exception);
864 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000865#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000866
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000867 // Generate the message.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000868 Handle<Object> message_obj;
869 MessageLocation potential_computed_location;
870 bool try_catch_needs_message =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000871 is_caught_externally &&
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000872 thread_local_.TryCatchHandler()->capture_message_;
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000873 if (report_exception || try_catch_needs_message) {
874 if (location == NULL) {
875 // If no location was specified we use a computed one instead
876 ComputeLocation(&potential_computed_location);
877 location = &potential_computed_location;
878 }
ager@chromium.org4af710e2009-09-15 12:20:11 +0000879 if (!Bootstrapper::IsActive()) {
880 // It's not safe to try to make message objects or collect stack
881 // traces while the bootstrapper is active since the infrastructure
882 // may not have been properly initialized.
883 Handle<String> stack_trace;
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000884 if (FLAG_trace_exception) stack_trace = StackTraceString();
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000885 Handle<JSArray> stack_trace_object;
886 if (report_exception && capture_stack_trace_for_uncaught_exceptions) {
887 stack_trace_object = Top::CaptureCurrentStackTrace(
888 stack_trace_for_uncaught_exceptions_frame_limit,
889 stack_trace_for_uncaught_exceptions_options);
890 }
lrn@chromium.org303ada72010-10-27 09:33:13 +0000891 ASSERT(is_object); // Can't use the handle unless there's a real object.
ager@chromium.org4af710e2009-09-15 12:20:11 +0000892 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000893 location, HandleVector<Object>(&exception_handle, 1), stack_trace,
894 stack_trace_object);
ager@chromium.org4af710e2009-09-15 12:20:11 +0000895 }
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000896 }
897
ager@chromium.org8bb60582008-12-11 12:02:20 +0000898 // Save the message for reporting if the the exception remains uncaught.
899 thread_local_.has_pending_message_ = report_exception;
900 thread_local_.pending_message_ = message;
901 if (!message_obj.is_null()) {
902 thread_local_.pending_message_obj_ = *message_obj;
903 if (location != NULL) {
904 thread_local_.pending_message_script_ = *location->script();
905 thread_local_.pending_message_start_pos_ = location->start_pos();
906 thread_local_.pending_message_end_pos_ = location->end_pos();
907 }
908 }
909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000910 if (is_caught_externally) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000911 thread_local_.catcher_ = thread_local_.TryCatchHandler();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 }
913
ager@chromium.org8bb60582008-12-11 12:02:20 +0000914 // NOTE: Notifying the debugger or generating the message
915 // may have caused new exceptions. For now, we just ignore
916 // that and set the pending exception to the original one.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000917 if (is_object) {
918 set_pending_exception(*exception_handle);
919 } else {
920 // Failures are not on the heap so they neither need nor work with handles.
921 ASSERT(exception_handle->IsFailure());
922 set_pending_exception(exception);
923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924}
925
926
ager@chromium.org8bb60582008-12-11 12:02:20 +0000927void Top::ReportPendingMessages() {
928 ASSERT(has_pending_exception());
929 setup_external_caught();
930 // If the pending exception is OutOfMemoryException set out_of_memory in
931 // the global context. Note: We have to mark the global context here
932 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
933 // set it.
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000934 bool external_caught = thread_local_.external_caught_exception_;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000935 HandleScope scope;
936 if (thread_local_.pending_exception_ == Failure::OutOfMemoryException()) {
937 context()->mark_out_of_memory();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000938 } else if (thread_local_.pending_exception_ ==
939 Heap::termination_exception()) {
940 if (external_caught) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000941 thread_local_.TryCatchHandler()->can_continue_ = false;
942 thread_local_.TryCatchHandler()->exception_ = Heap::null_value();
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000943 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000944 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000945 // At this point all non-object (failure) exceptions have
946 // been dealt with so this shouldn't fail.
947 Object* pending_exception_object = pending_exception()->ToObjectUnchecked();
948 Handle<Object> exception(pending_exception_object);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000949 thread_local_.external_caught_exception_ = false;
950 if (external_caught) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000951 thread_local_.TryCatchHandler()->can_continue_ = true;
952 thread_local_.TryCatchHandler()->exception_ =
ager@chromium.org8bb60582008-12-11 12:02:20 +0000953 thread_local_.pending_exception_;
954 if (!thread_local_.pending_message_obj_->IsTheHole()) {
955 try_catch_handler()->message_ = thread_local_.pending_message_obj_;
956 }
957 }
958 if (thread_local_.has_pending_message_) {
959 thread_local_.has_pending_message_ = false;
960 if (thread_local_.pending_message_ != NULL) {
961 MessageHandler::ReportMessage(thread_local_.pending_message_);
962 } else if (!thread_local_.pending_message_obj_->IsTheHole()) {
963 Handle<Object> message_obj(thread_local_.pending_message_obj_);
964 if (thread_local_.pending_message_script_ != NULL) {
965 Handle<Script> script(thread_local_.pending_message_script_);
966 int start_pos = thread_local_.pending_message_start_pos_;
967 int end_pos = thread_local_.pending_message_end_pos_;
968 MessageLocation location(script, start_pos, end_pos);
969 MessageHandler::ReportMessage(&location, message_obj);
970 } else {
971 MessageHandler::ReportMessage(NULL, message_obj);
972 }
973 }
974 }
975 thread_local_.external_caught_exception_ = external_caught;
976 set_pending_exception(*exception);
977 }
978 clear_pending_message();
979}
980
981
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982void Top::TraceException(bool flag) {
983 FLAG_trace_exception = flag;
984}
985
986
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000987bool Top::OptionalRescheduleException(bool is_bottom_call) {
ager@chromium.org71daaf62009-04-01 07:22:49 +0000988 // Allways reschedule out of memory exceptions.
989 if (!is_out_of_memory()) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000990 bool is_termination_exception =
991 pending_exception() == Heap::termination_exception();
ager@chromium.org71daaf62009-04-01 07:22:49 +0000992
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000993 // Do not reschedule the exception if this is the bottom call.
994 bool clear_exception = is_bottom_call;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000995
996 if (is_termination_exception) {
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000997 if (is_bottom_call) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000998 thread_local_.external_caught_exception_ = false;
sgjesse@chromium.orgc81c8942009-08-21 10:54:26 +0000999 clear_pending_exception();
1000 return false;
1001 }
1002 } else if (thread_local_.external_caught_exception_) {
1003 // If the exception is externally caught, clear it if there are no
1004 // JavaScript frames on the way to the C++ frame that has the
1005 // external handler.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001006 ASSERT(thread_local_.try_catch_handler_address() != NULL);
ager@chromium.org71daaf62009-04-01 07:22:49 +00001007 Address external_handler_address =
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001008 thread_local_.try_catch_handler_address();
ager@chromium.org71daaf62009-04-01 07:22:49 +00001009 JavaScriptFrameIterator it;
1010 if (it.done() || (it.frame()->sp() > external_handler_address)) {
1011 clear_exception = true;
1012 }
1013 }
1014
1015 // Clear the exception if needed.
1016 if (clear_exception) {
1017 thread_local_.external_caught_exception_ = false;
1018 clear_pending_exception();
1019 return false;
1020 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 }
ager@chromium.org71daaf62009-04-01 07:22:49 +00001022
1023 // Reschedule the exception.
1024 thread_local_.scheduled_exception_ = pending_exception();
1025 clear_pending_exception();
1026 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027}
1028
1029
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00001030void Top::SetCaptureStackTraceForUncaughtExceptions(
1031 bool capture,
1032 int frame_limit,
1033 StackTrace::StackTraceOptions options) {
1034 capture_stack_trace_for_uncaught_exceptions = capture;
1035 stack_trace_for_uncaught_exceptions_frame_limit = frame_limit;
1036 stack_trace_for_uncaught_exceptions_options = options;
1037}
1038
1039
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040bool Top::is_out_of_memory() {
1041 if (has_pending_exception()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001042 MaybeObject* e = pending_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001043 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1044 return true;
1045 }
1046 }
1047 if (has_scheduled_exception()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00001048 MaybeObject* e = scheduled_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001049 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
1050 return true;
1051 }
1052 }
1053 return false;
1054}
1055
1056
1057Handle<Context> Top::global_context() {
1058 GlobalObject* global = thread_local_.context_->global();
1059 return Handle<Context>(global->global_context());
1060}
1061
1062
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00001063Handle<Context> Top::GetCallingGlobalContext() {
1064 JavaScriptFrameIterator it;
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001065#ifdef ENABLE_DEBUGGER_SUPPORT
1066 if (Debug::InDebugger()) {
1067 while (!it.done()) {
1068 JavaScriptFrame* frame = it.frame();
1069 Context* context = Context::cast(frame->context());
1070 if (context->global_context() == *Debug::debug_context()) {
1071 it.Advance();
1072 } else {
1073 break;
1074 }
1075 }
1076 }
1077#endif // ENABLE_DEBUGGER_SUPPORT
ager@chromium.org1bf0cd02009-05-20 11:34:19 +00001078 if (it.done()) return Handle<Context>::null();
1079 JavaScriptFrame* frame = it.frame();
1080 Context* context = Context::cast(frame->context());
1081 return Handle<Context>(context->global_context());
1082}
1083
1084
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085char* Top::ArchiveThread(char* to) {
1086 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(thread_local_));
kasper.lundaf4734f2008-07-28 12:50:18 +00001087 InitializeThreadLocal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 return to + sizeof(thread_local_);
1089}
1090
1091
1092char* Top::RestoreThread(char* from) {
1093 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(thread_local_));
lrn@chromium.org303ada72010-10-27 09:33:13 +00001094 // This might be just paranoia, but it seems to be needed in case a
1095 // thread_local_ is restored on a separate OS thread.
1096#ifdef USE_SIMULATOR
1097#ifdef V8_TARGET_ARCH_ARM
ager@chromium.org378b34e2011-01-28 08:04:38 +00001098 thread_local_.simulator_ = Simulator::current();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001099#elif V8_TARGET_ARCH_MIPS
1100 thread_local_.simulator_ = assembler::mips::Simulator::current();
1101#endif
1102#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103 return from + sizeof(thread_local_);
1104}
1105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106} } // namespace v8::internal