1 // Copyright 2011 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 "compiler.h"
33 #include "debug.h"
34 #include "execution.h"
35 #include "messages.h"
36 #include "platform.h"
37 #include "simulator.h"
38 #include "string-stream.h"
39 #include "vm-state-inl.h"
40
41
42 // TODO(isolates): move to isolate.cc. This stuff is kept here to
43 // simplify merging.
44
45 namespace v8 {
46 namespace internal {
47
ThreadLocalTop()48 ThreadLocalTop::ThreadLocalTop() {
49 InitializeInternal();
50 // This flag may be set using v8::V8::IgnoreOutOfMemoryException()
51 // before an isolate is initialized. The initialize methods below do
52 // not touch it to preserve its value.
53 ignore_out_of_memory_ = false;
54 }
55
56
InitializeInternal()57 void ThreadLocalTop::InitializeInternal() {
58 c_entry_fp_ = 0;
59 handler_ = 0;
60 #ifdef USE_SIMULATOR
61 simulator_ = NULL;
62 #endif
63 #ifdef ENABLE_LOGGING_AND_PROFILING
64 js_entry_sp_ = NULL;
65 external_callback_ = NULL;
66 #endif
67 #ifdef ENABLE_VMSTATE_TRACKING
68 current_vm_state_ = EXTERNAL;
69 #endif
70 try_catch_handler_address_ = NULL;
71 context_ = NULL;
72 thread_id_ = ThreadId::Invalid();
73 external_caught_exception_ = false;
74 failed_access_check_callback_ = NULL;
75 save_context_ = NULL;
76 catcher_ = NULL;
77 }
78
79
Initialize()80 void ThreadLocalTop::Initialize() {
81 InitializeInternal();
82 #ifdef USE_SIMULATOR
83 #ifdef V8_TARGET_ARCH_ARM
84 simulator_ = Simulator::current(Isolate::Current());
85 #elif V8_TARGET_ARCH_MIPS
86 simulator_ = Simulator::current(Isolate::Current());
87 #endif
88 #endif
89 thread_id_ = ThreadId::Current();
90 }
91
92
TryCatchHandler()93 v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
94 return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
95 }
96
97
get_address_from_id(Isolate::AddressId id)98 Address Isolate::get_address_from_id(Isolate::AddressId id) {
99 return isolate_addresses_[id];
100 }
101
102
Iterate(ObjectVisitor * v,char * thread_storage)103 char* Isolate::Iterate(ObjectVisitor* v, char* thread_storage) {
104 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(thread_storage);
105 Iterate(v, thread);
106 return thread_storage + sizeof(ThreadLocalTop);
107 }
108
109
IterateThread(ThreadVisitor * v)110 void Isolate::IterateThread(ThreadVisitor* v) {
111 v->VisitThread(this, thread_local_top());
112 }
113
114
IterateThread(ThreadVisitor * v,char * t)115 void Isolate::IterateThread(ThreadVisitor* v, char* t) {
116 ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
117 v->VisitThread(this, thread);
118 }
119
120
Iterate(ObjectVisitor * v,ThreadLocalTop * thread)121 void Isolate::Iterate(ObjectVisitor* v, ThreadLocalTop* thread) {
122 // Visit the roots from the top for a given thread.
123 Object* pending;
124 // The pending exception can sometimes be a failure. We can't show
125 // that to the GC, which only understands objects.
126 if (thread->pending_exception_->ToObject(&pending)) {
127 v->VisitPointer(&pending);
128 thread->pending_exception_ = pending; // In case GC updated it.
129 }
130 v->VisitPointer(&(thread->pending_message_obj_));
131 v->VisitPointer(BitCast<Object**>(&(thread->pending_message_script_)));
132 v->VisitPointer(BitCast<Object**>(&(thread->context_)));
133 Object* scheduled;
134 if (thread->scheduled_exception_->ToObject(&scheduled)) {
135 v->VisitPointer(&scheduled);
136 thread->scheduled_exception_ = scheduled;
137 }
138
139 for (v8::TryCatch* block = thread->TryCatchHandler();
140 block != NULL;
141 block = TRY_CATCH_FROM_ADDRESS(block->next_)) {
142 v->VisitPointer(BitCast<Object**>(&(block->exception_)));
143 v->VisitPointer(BitCast<Object**>(&(block->message_)));
144 }
145
146 // Iterate over pointers on native execution stack.
147 for (StackFrameIterator it(this, thread); !it.done(); it.Advance()) {
148 it.frame()->Iterate(v);
149 }
150 }
151
152
Iterate(ObjectVisitor * v)153 void Isolate::Iterate(ObjectVisitor* v) {
154 ThreadLocalTop* current_t = thread_local_top();
155 Iterate(v, current_t);
156 }
157
158
RegisterTryCatchHandler(v8::TryCatch * that)159 void Isolate::RegisterTryCatchHandler(v8::TryCatch* that) {
160 // The ARM simulator has a separate JS stack. We therefore register
161 // the C++ try catch handler with the simulator and get back an
162 // address that can be used for comparisons with addresses into the
163 // JS stack. When running without the simulator, the address
164 // returned will be the address of the C++ try catch handler itself.
165 Address address = reinterpret_cast<Address>(
166 SimulatorStack::RegisterCTryCatch(reinterpret_cast<uintptr_t>(that)));
167 thread_local_top()->set_try_catch_handler_address(address);
168 }
169
170
UnregisterTryCatchHandler(v8::TryCatch * that)171 void Isolate::UnregisterTryCatchHandler(v8::TryCatch* that) {
172 ASSERT(thread_local_top()->TryCatchHandler() == that);
173 thread_local_top()->set_try_catch_handler_address(
174 reinterpret_cast<Address>(that->next_));
175 thread_local_top()->catcher_ = NULL;
176 SimulatorStack::UnregisterCTryCatch();
177 }
178
179
StackTraceString()180 Handle<String> Isolate::StackTraceString() {
181 if (stack_trace_nesting_level_ == 0) {
182 stack_trace_nesting_level_++;
183 HeapStringAllocator allocator;
184 StringStream::ClearMentionedObjectCache();
185 StringStream accumulator(&allocator);
186 incomplete_message_ = &accumulator;
187 PrintStack(&accumulator);
188 Handle<String> stack_trace = accumulator.ToString();
189 incomplete_message_ = NULL;
190 stack_trace_nesting_level_ = 0;
191 return stack_trace;
192 } else if (stack_trace_nesting_level_ == 1) {
193 stack_trace_nesting_level_++;
194 OS::PrintError(
195 "\n\nAttempt to print stack while printing stack (double fault)\n");
196 OS::PrintError(
197 "If you are lucky you may find a partial stack dump on stdout.\n\n");
198 incomplete_message_->OutputToStdOut();
199 return factory()->empty_symbol();
200 } else {
201 OS::Abort();
202 // Unreachable
203 return factory()->empty_symbol();
204 }
205 }
206
207
CaptureCurrentStackTrace(int frame_limit,StackTrace::StackTraceOptions options)208 Handle<JSArray> Isolate::CaptureCurrentStackTrace(
209 int frame_limit, StackTrace::StackTraceOptions options) {
210 // Ensure no negative values.
211 int limit = Max(frame_limit, 0);
212 Handle<JSArray> stack_trace = factory()->NewJSArray(frame_limit);
213
214 Handle<String> column_key = factory()->LookupAsciiSymbol("column");
215 Handle<String> line_key = factory()->LookupAsciiSymbol("lineNumber");
216 Handle<String> script_key = factory()->LookupAsciiSymbol("scriptName");
217 Handle<String> name_or_source_url_key =
218 factory()->LookupAsciiSymbol("nameOrSourceURL");
219 Handle<String> script_name_or_source_url_key =
220 factory()->LookupAsciiSymbol("scriptNameOrSourceURL");
221 Handle<String> function_key = factory()->LookupAsciiSymbol("functionName");
222 Handle<String> eval_key = factory()->LookupAsciiSymbol("isEval");
223 Handle<String> constructor_key =
224 factory()->LookupAsciiSymbol("isConstructor");
225
226 StackTraceFrameIterator it(this);
227 int frames_seen = 0;
228 while (!it.done() && (frames_seen < limit)) {
229 JavaScriptFrame* frame = it.frame();
230 // Set initial size to the maximum inlining level + 1 for the outermost
231 // function.
232 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
233 frame->Summarize(&frames);
234 for (int i = frames.length() - 1; i >= 0 && frames_seen < limit; i--) {
235 // Create a JSObject to hold the information for the StackFrame.
236 Handle<JSObject> stackFrame = factory()->NewJSObject(object_function());
237
238 Handle<JSFunction> fun = frames[i].function();
239 Handle<Script> script(Script::cast(fun->shared()->script()));
240
241 if (options & StackTrace::kLineNumber) {
242 int script_line_offset = script->line_offset()->value();
243 int position = frames[i].code()->SourcePosition(frames[i].pc());
244 int line_number = GetScriptLineNumber(script, position);
245 // line_number is already shifted by the script_line_offset.
246 int relative_line_number = line_number - script_line_offset;
247 if (options & StackTrace::kColumnOffset && relative_line_number >= 0) {
248 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
249 int start = (relative_line_number == 0) ? 0 :
250 Smi::cast(line_ends->get(relative_line_number - 1))->value() + 1;
251 int column_offset = position - start;
252 if (relative_line_number == 0) {
253 // For the case where the code is on the same line as the script
254 // tag.
255 column_offset += script->column_offset()->value();
256 }
257 SetLocalPropertyNoThrow(stackFrame, column_key,
258 Handle<Smi>(Smi::FromInt(column_offset + 1)));
259 }
260 SetLocalPropertyNoThrow(stackFrame, line_key,
261 Handle<Smi>(Smi::FromInt(line_number + 1)));
262 }
263
264 if (options & StackTrace::kScriptName) {
265 Handle<Object> script_name(script->name(), this);
266 SetLocalPropertyNoThrow(stackFrame, script_key, script_name);
267 }
268
269 if (options & StackTrace::kScriptNameOrSourceURL) {
270 Handle<Object> script_name(script->name(), this);
271 Handle<JSValue> script_wrapper = GetScriptWrapper(script);
272 Handle<Object> property = GetProperty(script_wrapper,
273 name_or_source_url_key);
274 ASSERT(property->IsJSFunction());
275 Handle<JSFunction> method = Handle<JSFunction>::cast(property);
276 bool caught_exception;
277 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0,
278 NULL, &caught_exception);
279 if (caught_exception) {
280 result = factory()->undefined_value();
281 }
282 SetLocalPropertyNoThrow(stackFrame, script_name_or_source_url_key,
283 result);
284 }
285
286 if (options & StackTrace::kFunctionName) {
287 Handle<Object> fun_name(fun->shared()->name(), this);
288 if (fun_name->ToBoolean()->IsFalse()) {
289 fun_name = Handle<Object>(fun->shared()->inferred_name(), this);
290 }
291 SetLocalPropertyNoThrow(stackFrame, function_key, fun_name);
292 }
293
294 if (options & StackTrace::kIsEval) {
295 int type = Smi::cast(script->compilation_type())->value();
296 Handle<Object> is_eval = (type == Script::COMPILATION_TYPE_EVAL) ?
297 factory()->true_value() : factory()->false_value();
298 SetLocalPropertyNoThrow(stackFrame, eval_key, is_eval);
299 }
300
301 if (options & StackTrace::kIsConstructor) {
302 Handle<Object> is_constructor = (frames[i].is_constructor()) ?
303 factory()->true_value() : factory()->false_value();
304 SetLocalPropertyNoThrow(stackFrame, constructor_key, is_constructor);
305 }
306
307 FixedArray::cast(stack_trace->elements())->set(frames_seen, *stackFrame);
308 frames_seen++;
309 }
310 it.Advance();
311 }
312
313 stack_trace->set_length(Smi::FromInt(frames_seen));
314 return stack_trace;
315 }
316
317
PrintStack()318 void Isolate::PrintStack() {
319 if (stack_trace_nesting_level_ == 0) {
320 stack_trace_nesting_level_++;
321
322 StringAllocator* allocator;
323 if (preallocated_message_space_ == NULL) {
324 allocator = new HeapStringAllocator();
325 } else {
326 allocator = preallocated_message_space_;
327 }
328
329 StringStream::ClearMentionedObjectCache();
330 StringStream accumulator(allocator);
331 incomplete_message_ = &accumulator;
332 PrintStack(&accumulator);
333 accumulator.OutputToStdOut();
334 InitializeLoggingAndCounters();
335 accumulator.Log();
336 incomplete_message_ = NULL;
337 stack_trace_nesting_level_ = 0;
338 if (preallocated_message_space_ == NULL) {
339 // Remove the HeapStringAllocator created above.
340 delete allocator;
341 }
342 } else if (stack_trace_nesting_level_ == 1) {
343 stack_trace_nesting_level_++;
344 OS::PrintError(
345 "\n\nAttempt to print stack while printing stack (double fault)\n");
346 OS::PrintError(
347 "If you are lucky you may find a partial stack dump on stdout.\n\n");
348 incomplete_message_->OutputToStdOut();
349 }
350 }
351
352
PrintFrames(StringStream * accumulator,StackFrame::PrintMode mode)353 static void PrintFrames(StringStream* accumulator,
354 StackFrame::PrintMode mode) {
355 StackFrameIterator it;
356 for (int i = 0; !it.done(); it.Advance()) {
357 it.frame()->Print(accumulator, mode, i++);
358 }
359 }
360
361
PrintStack(StringStream * accumulator)362 void Isolate::PrintStack(StringStream* accumulator) {
363 if (!IsInitialized()) {
364 accumulator->Add(
365 "\n==== Stack trace is not available ==========================\n\n");
366 accumulator->Add(
367 "\n==== Isolate for the thread is not initialized =============\n\n");
368 return;
369 }
370 // The MentionedObjectCache is not GC-proof at the moment.
371 AssertNoAllocation nogc;
372 ASSERT(StringStream::IsMentionedObjectCacheClear());
373
374 // Avoid printing anything if there are no frames.
375 if (c_entry_fp(thread_local_top()) == 0) return;
376
377 accumulator->Add(
378 "\n==== Stack trace ============================================\n\n");
379 PrintFrames(accumulator, StackFrame::OVERVIEW);
380
381 accumulator->Add(
382 "\n==== Details ================================================\n\n");
383 PrintFrames(accumulator, StackFrame::DETAILS);
384
385 accumulator->PrintMentionedObjectCache();
386 accumulator->Add("=====================\n\n");
387 }
388
389
SetFailedAccessCheckCallback(v8::FailedAccessCheckCallback callback)390 void Isolate::SetFailedAccessCheckCallback(
391 v8::FailedAccessCheckCallback callback) {
392 thread_local_top()->failed_access_check_callback_ = callback;
393 }
394
395
ReportFailedAccessCheck(JSObject * receiver,v8::AccessType type)396 void Isolate::ReportFailedAccessCheck(JSObject* receiver, v8::AccessType type) {
397 if (!thread_local_top()->failed_access_check_callback_) return;
398
399 ASSERT(receiver->IsAccessCheckNeeded());
400 ASSERT(context());
401
402 // Get the data object from access check info.
403 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
404 if (!constructor->shared()->IsApiFunction()) return;
405 Object* data_obj =
406 constructor->shared()->get_api_func_data()->access_check_info();
407 if (data_obj == heap_.undefined_value()) return;
408
409 HandleScope scope;
410 Handle<JSObject> receiver_handle(receiver);
411 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data());
412 thread_local_top()->failed_access_check_callback_(
413 v8::Utils::ToLocal(receiver_handle),
414 type,
415 v8::Utils::ToLocal(data));
416 }
417
418
419 enum MayAccessDecision {
420 YES, NO, UNKNOWN
421 };
422
423
MayAccessPreCheck(Isolate * isolate,JSObject * receiver,v8::AccessType type)424 static MayAccessDecision MayAccessPreCheck(Isolate* isolate,
425 JSObject* receiver,
426 v8::AccessType type) {
427 // During bootstrapping, callback functions are not enabled yet.
428 if (isolate->bootstrapper()->IsActive()) return YES;
429
430 if (receiver->IsJSGlobalProxy()) {
431 Object* receiver_context = JSGlobalProxy::cast(receiver)->context();
432 if (!receiver_context->IsContext()) return NO;
433
434 // Get the global context of current top context.
435 // avoid using Isolate::global_context() because it uses Handle.
436 Context* global_context = isolate->context()->global()->global_context();
437 if (receiver_context == global_context) return YES;
438
439 if (Context::cast(receiver_context)->security_token() ==
440 global_context->security_token())
441 return YES;
442 }
443
444 return UNKNOWN;
445 }
446
447
MayNamedAccess(JSObject * receiver,Object * key,v8::AccessType type)448 bool Isolate::MayNamedAccess(JSObject* receiver, Object* key,
449 v8::AccessType type) {
450 ASSERT(receiver->IsAccessCheckNeeded());
451
452 // The callers of this method are not expecting a GC.
453 AssertNoAllocation no_gc;
454
455 // Skip checks for hidden properties access. Note, we do not
456 // require existence of a context in this case.
457 if (key == heap_.hidden_symbol()) return true;
458
459 // Check for compatibility between the security tokens in the
460 // current lexical context and the accessed object.
461 ASSERT(context());
462
463 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
464 if (decision != UNKNOWN) return decision == YES;
465
466 // Get named access check callback
467 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
468 if (!constructor->shared()->IsApiFunction()) return false;
469
470 Object* data_obj =
471 constructor->shared()->get_api_func_data()->access_check_info();
472 if (data_obj == heap_.undefined_value()) return false;
473
474 Object* fun_obj = AccessCheckInfo::cast(data_obj)->named_callback();
475 v8::NamedSecurityCallback callback =
476 v8::ToCData<v8::NamedSecurityCallback>(fun_obj);
477
478 if (!callback) return false;
479
480 HandleScope scope(this);
481 Handle<JSObject> receiver_handle(receiver, this);
482 Handle<Object> key_handle(key, this);
483 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
484 LOG(this, ApiNamedSecurityCheck(key));
485 bool result = false;
486 {
487 // Leaving JavaScript.
488 VMState state(this, EXTERNAL);
489 result = callback(v8::Utils::ToLocal(receiver_handle),
490 v8::Utils::ToLocal(key_handle),
491 type,
492 v8::Utils::ToLocal(data));
493 }
494 return result;
495 }
496
497
MayIndexedAccess(JSObject * receiver,uint32_t index,v8::AccessType type)498 bool Isolate::MayIndexedAccess(JSObject* receiver,
499 uint32_t index,
500 v8::AccessType type) {
501 ASSERT(receiver->IsAccessCheckNeeded());
502 // Check for compatibility between the security tokens in the
503 // current lexical context and the accessed object.
504 ASSERT(context());
505
506 MayAccessDecision decision = MayAccessPreCheck(this, receiver, type);
507 if (decision != UNKNOWN) return decision == YES;
508
509 // Get indexed access check callback
510 JSFunction* constructor = JSFunction::cast(receiver->map()->constructor());
511 if (!constructor->shared()->IsApiFunction()) return false;
512
513 Object* data_obj =
514 constructor->shared()->get_api_func_data()->access_check_info();
515 if (data_obj == heap_.undefined_value()) return false;
516
517 Object* fun_obj = AccessCheckInfo::cast(data_obj)->indexed_callback();
518 v8::IndexedSecurityCallback callback =
519 v8::ToCData<v8::IndexedSecurityCallback>(fun_obj);
520
521 if (!callback) return false;
522
523 HandleScope scope(this);
524 Handle<JSObject> receiver_handle(receiver, this);
525 Handle<Object> data(AccessCheckInfo::cast(data_obj)->data(), this);
526 LOG(this, ApiIndexedSecurityCheck(index));
527 bool result = false;
528 {
529 // Leaving JavaScript.
530 VMState state(this, EXTERNAL);
531 result = callback(v8::Utils::ToLocal(receiver_handle),
532 index,
533 type,
534 v8::Utils::ToLocal(data));
535 }
536 return result;
537 }
538
539
540 const char* const Isolate::kStackOverflowMessage =
541 "Uncaught RangeError: Maximum call stack size exceeded";
542
543
StackOverflow()544 Failure* Isolate::StackOverflow() {
545 HandleScope scope;
546 Handle<String> key = factory()->stack_overflow_symbol();
547 Handle<JSObject> boilerplate =
548 Handle<JSObject>::cast(GetProperty(js_builtins_object(), key));
549 Handle<Object> exception = Copy(boilerplate);
550 // TODO(1240995): To avoid having to call JavaScript code to compute
551 // the message for stack overflow exceptions which is very likely to
552 // double fault with another stack overflow exception, we use a
553 // precomputed message.
554 DoThrow(*exception, NULL);
555 return Failure::Exception();
556 }
557
558
TerminateExecution()559 Failure* Isolate::TerminateExecution() {
560 DoThrow(heap_.termination_exception(), NULL);
561 return Failure::Exception();
562 }
563
564
Throw(Object * exception,MessageLocation * location)565 Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
566 DoThrow(exception, location);
567 return Failure::Exception();
568 }
569
570
ReThrow(MaybeObject * exception,MessageLocation * location)571 Failure* Isolate::ReThrow(MaybeObject* exception, MessageLocation* location) {
572 bool can_be_caught_externally = false;
573 ShouldReportException(&can_be_caught_externally,
574 is_catchable_by_javascript(exception));
575 thread_local_top()->catcher_ = can_be_caught_externally ?
576 try_catch_handler() : NULL;
577
578 // Set the exception being re-thrown.
579 set_pending_exception(exception);
580 if (exception->IsFailure()) return exception->ToFailureUnchecked();
581 return Failure::Exception();
582 }
583
584
ThrowIllegalOperation()585 Failure* Isolate::ThrowIllegalOperation() {
586 return Throw(heap_.illegal_access_symbol());
587 }
588
589
ScheduleThrow(Object * exception)590 void Isolate::ScheduleThrow(Object* exception) {
591 // When scheduling a throw we first throw the exception to get the
592 // error reporting if it is uncaught before rescheduling it.
593 Throw(exception);
594 thread_local_top()->scheduled_exception_ = pending_exception();
595 thread_local_top()->external_caught_exception_ = false;
596 clear_pending_exception();
597 }
598
599
PromoteScheduledException()600 Failure* Isolate::PromoteScheduledException() {
601 MaybeObject* thrown = scheduled_exception();
602 clear_scheduled_exception();
603 // Re-throw the exception to avoid getting repeated error reporting.
604 return ReThrow(thrown);
605 }
606
607
PrintCurrentStackTrace(FILE * out)608 void Isolate::PrintCurrentStackTrace(FILE* out) {
609 StackTraceFrameIterator it(this);
610 while (!it.done()) {
611 HandleScope scope;
612 // Find code position if recorded in relocation info.
613 JavaScriptFrame* frame = it.frame();
614 int pos = frame->LookupCode()->SourcePosition(frame->pc());
615 Handle<Object> pos_obj(Smi::FromInt(pos));
616 // Fetch function and receiver.
617 Handle<JSFunction> fun(JSFunction::cast(frame->function()));
618 Handle<Object> recv(frame->receiver());
619 // Advance to the next JavaScript frame and determine if the
620 // current frame is the top-level frame.
621 it.Advance();
622 Handle<Object> is_top_level = it.done()
623 ? factory()->true_value()
624 : factory()->false_value();
625 // Generate and print stack trace line.
626 Handle<String> line =
627 Execution::GetStackTraceLine(recv, fun, pos_obj, is_top_level);
628 if (line->length() > 0) {
629 line->PrintOn(out);
630 fprintf(out, "\n");
631 }
632 }
633 }
634
635
ComputeLocation(MessageLocation * target)636 void Isolate::ComputeLocation(MessageLocation* target) {
637 *target = MessageLocation(Handle<Script>(heap_.empty_script()), -1, -1);
638 StackTraceFrameIterator it(this);
639 if (!it.done()) {
640 JavaScriptFrame* frame = it.frame();
641 JSFunction* fun = JSFunction::cast(frame->function());
642 Object* script = fun->shared()->script();
643 if (script->IsScript() &&
644 !(Script::cast(script)->source()->IsUndefined())) {
645 int pos = frame->LookupCode()->SourcePosition(frame->pc());
646 // Compute the location from the function and the reloc info.
647 Handle<Script> casted_script(Script::cast(script));
648 *target = MessageLocation(casted_script, pos, pos + 1);
649 }
650 }
651 }
652
653
ShouldReportException(bool * can_be_caught_externally,bool catchable_by_javascript)654 bool Isolate::ShouldReportException(bool* can_be_caught_externally,
655 bool catchable_by_javascript) {
656 // Find the top-most try-catch handler.
657 StackHandler* handler =
658 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
659 while (handler != NULL && !handler->is_try_catch()) {
660 handler = handler->next();
661 }
662
663 // Get the address of the external handler so we can compare the address to
664 // determine which one is closer to the top of the stack.
665 Address external_handler_address =
666 thread_local_top()->try_catch_handler_address();
667
668 // The exception has been externally caught if and only if there is
669 // an external handler which is on top of the top-most try-catch
670 // handler.
671 *can_be_caught_externally = external_handler_address != NULL &&
672 (handler == NULL || handler->address() > external_handler_address ||
673 !catchable_by_javascript);
674
675 if (*can_be_caught_externally) {
676 // Only report the exception if the external handler is verbose.
677 return try_catch_handler()->is_verbose_;
678 } else {
679 // Report the exception if it isn't caught by JavaScript code.
680 return handler == NULL;
681 }
682 }
683
684
DoThrow(MaybeObject * exception,MessageLocation * location)685 void Isolate::DoThrow(MaybeObject* exception, MessageLocation* location) {
686 ASSERT(!has_pending_exception());
687
688 HandleScope scope;
689 Object* exception_object = Smi::FromInt(0);
690 bool is_object = exception->ToObject(&exception_object);
691 Handle<Object> exception_handle(exception_object);
692
693 // Determine reporting and whether the exception is caught externally.
694 bool catchable_by_javascript = is_catchable_by_javascript(exception);
695 // Only real objects can be caught by JS.
696 ASSERT(!catchable_by_javascript || is_object);
697 bool can_be_caught_externally = false;
698 bool should_report_exception =
699 ShouldReportException(&can_be_caught_externally, catchable_by_javascript);
700 bool report_exception = catchable_by_javascript && should_report_exception;
701
702 #ifdef ENABLE_DEBUGGER_SUPPORT
703 // Notify debugger of exception.
704 if (catchable_by_javascript) {
705 debugger_->OnException(exception_handle, report_exception);
706 }
707 #endif
708
709 // Generate the message.
710 Handle<Object> message_obj;
711 MessageLocation potential_computed_location;
712 bool try_catch_needs_message =
713 can_be_caught_externally &&
714 try_catch_handler()->capture_message_;
715 if (report_exception || try_catch_needs_message) {
716 if (location == NULL) {
717 // If no location was specified we use a computed one instead
718 ComputeLocation(&potential_computed_location);
719 location = &potential_computed_location;
720 }
721 if (!bootstrapper()->IsActive()) {
722 // It's not safe to try to make message objects or collect stack
723 // traces while the bootstrapper is active since the infrastructure
724 // may not have been properly initialized.
725 Handle<String> stack_trace;
726 if (FLAG_trace_exception) stack_trace = StackTraceString();
727 Handle<JSArray> stack_trace_object;
728 if (report_exception && capture_stack_trace_for_uncaught_exceptions_) {
729 stack_trace_object = CaptureCurrentStackTrace(
730 stack_trace_for_uncaught_exceptions_frame_limit_,
731 stack_trace_for_uncaught_exceptions_options_);
732 }
733 ASSERT(is_object); // Can't use the handle unless there's a real object.
734 message_obj = MessageHandler::MakeMessageObject("uncaught_exception",
735 location, HandleVector<Object>(&exception_handle, 1), stack_trace,
736 stack_trace_object);
737 }
738 }
739
740 // Save the message for reporting if the the exception remains uncaught.
741 thread_local_top()->has_pending_message_ = report_exception;
742 if (!message_obj.is_null()) {
743 thread_local_top()->pending_message_obj_ = *message_obj;
744 if (location != NULL) {
745 thread_local_top()->pending_message_script_ = *location->script();
746 thread_local_top()->pending_message_start_pos_ = location->start_pos();
747 thread_local_top()->pending_message_end_pos_ = location->end_pos();
748 }
749 }
750
751 // Do not forget to clean catcher_ if currently thrown exception cannot
752 // be caught. If necessary, ReThrow will update the catcher.
753 thread_local_top()->catcher_ = can_be_caught_externally ?
754 try_catch_handler() : NULL;
755
756 // NOTE: Notifying the debugger or generating the message
757 // may have caused new exceptions. For now, we just ignore
758 // that and set the pending exception to the original one.
759 if (is_object) {
760 set_pending_exception(*exception_handle);
761 } else {
762 // Failures are not on the heap so they neither need nor work with handles.
763 ASSERT(exception_handle->IsFailure());
764 set_pending_exception(exception);
765 }
766 }
767
768
IsExternallyCaught()769 bool Isolate::IsExternallyCaught() {
770 ASSERT(has_pending_exception());
771
772 if ((thread_local_top()->catcher_ == NULL) ||
773 (try_catch_handler() != thread_local_top()->catcher_)) {
774 // When throwing the exception, we found no v8::TryCatch
775 // which should care about this exception.
776 return false;
777 }
778
779 if (!is_catchable_by_javascript(pending_exception())) {
780 return true;
781 }
782
783 // Get the address of the external handler so we can compare the address to
784 // determine which one is closer to the top of the stack.
785 Address external_handler_address =
786 thread_local_top()->try_catch_handler_address();
787 ASSERT(external_handler_address != NULL);
788
789 // The exception has been externally caught if and only if there is
790 // an external handler which is on top of the top-most try-finally
791 // handler.
792 // There should be no try-catch blocks as they would prohibit us from
793 // finding external catcher in the first place (see catcher_ check above).
794 //
795 // Note, that finally clause would rethrow an exception unless it's
796 // aborted by jumps in control flow like return, break, etc. and we'll
797 // have another chances to set proper v8::TryCatch.
798 StackHandler* handler =
799 StackHandler::FromAddress(Isolate::handler(thread_local_top()));
800 while (handler != NULL && handler->address() < external_handler_address) {
801 ASSERT(!handler->is_try_catch());
802 if (handler->is_try_finally()) return false;
803
804 handler = handler->next();
805 }
806
807 return true;
808 }
809
810
ReportPendingMessages()811 void Isolate::ReportPendingMessages() {
812 ASSERT(has_pending_exception());
813 PropagatePendingExceptionToExternalTryCatch();
814
815 // If the pending exception is OutOfMemoryException set out_of_memory in
816 // the global context. Note: We have to mark the global context here
817 // since the GenerateThrowOutOfMemory stub cannot make a RuntimeCall to
818 // set it.
819 HandleScope scope;
820 if (thread_local_top_.pending_exception_ == Failure::OutOfMemoryException()) {
821 context()->mark_out_of_memory();
822 } else if (thread_local_top_.pending_exception_ ==
823 heap()->termination_exception()) {
824 // Do nothing: if needed, the exception has been already propagated to
825 // v8::TryCatch.
826 } else {
827 if (thread_local_top_.has_pending_message_) {
828 thread_local_top_.has_pending_message_ = false;
829 if (!thread_local_top_.pending_message_obj_->IsTheHole()) {
830 HandleScope scope;
831 Handle<Object> message_obj(thread_local_top_.pending_message_obj_);
832 if (thread_local_top_.pending_message_script_ != NULL) {
833 Handle<Script> script(thread_local_top_.pending_message_script_);
834 int start_pos = thread_local_top_.pending_message_start_pos_;
835 int end_pos = thread_local_top_.pending_message_end_pos_;
836 MessageLocation location(script, start_pos, end_pos);
837 MessageHandler::ReportMessage(this, &location, message_obj);
838 } else {
839 MessageHandler::ReportMessage(this, NULL, message_obj);
840 }
841 }
842 }
843 }
844 clear_pending_message();
845 }
846
847
TraceException(bool flag)848 void Isolate::TraceException(bool flag) {
849 FLAG_trace_exception = flag; // TODO(isolates): This is an unfortunate use.
850 }
851
852
OptionalRescheduleException(bool is_bottom_call)853 bool Isolate::OptionalRescheduleException(bool is_bottom_call) {
854 ASSERT(has_pending_exception());
855 PropagatePendingExceptionToExternalTryCatch();
856
857 // Allways reschedule out of memory exceptions.
858 if (!is_out_of_memory()) {
859 bool is_termination_exception =
860 pending_exception() == heap_.termination_exception();
861
862 // Do not reschedule the exception if this is the bottom call.
863 bool clear_exception = is_bottom_call;
864
865 if (is_termination_exception) {
866 if (is_bottom_call) {
867 thread_local_top()->external_caught_exception_ = false;
868 clear_pending_exception();
869 return false;
870 }
871 } else if (thread_local_top()->external_caught_exception_) {
872 // If the exception is externally caught, clear it if there are no
873 // JavaScript frames on the way to the C++ frame that has the
874 // external handler.
875 ASSERT(thread_local_top()->try_catch_handler_address() != NULL);
876 Address external_handler_address =
877 thread_local_top()->try_catch_handler_address();
878 JavaScriptFrameIterator it;
879 if (it.done() || (it.frame()->sp() > external_handler_address)) {
880 clear_exception = true;
881 }
882 }
883
884 // Clear the exception if needed.
885 if (clear_exception) {
886 thread_local_top()->external_caught_exception_ = false;
887 clear_pending_exception();
888 return false;
889 }
890 }
891
892 // Reschedule the exception.
893 thread_local_top()->scheduled_exception_ = pending_exception();
894 clear_pending_exception();
895 return true;
896 }
897
898
SetCaptureStackTraceForUncaughtExceptions(bool capture,int frame_limit,StackTrace::StackTraceOptions options)899 void Isolate::SetCaptureStackTraceForUncaughtExceptions(
900 bool capture,
901 int frame_limit,
902 StackTrace::StackTraceOptions options) {
903 capture_stack_trace_for_uncaught_exceptions_ = capture;
904 stack_trace_for_uncaught_exceptions_frame_limit_ = frame_limit;
905 stack_trace_for_uncaught_exceptions_options_ = options;
906 }
907
908
is_out_of_memory()909 bool Isolate::is_out_of_memory() {
910 if (has_pending_exception()) {
911 MaybeObject* e = pending_exception();
912 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
913 return true;
914 }
915 }
916 if (has_scheduled_exception()) {
917 MaybeObject* e = scheduled_exception();
918 if (e->IsFailure() && Failure::cast(e)->IsOutOfMemoryException()) {
919 return true;
920 }
921 }
922 return false;
923 }
924
925
global_context()926 Handle<Context> Isolate::global_context() {
927 GlobalObject* global = thread_local_top()->context_->global();
928 return Handle<Context>(global->global_context());
929 }
930
931
GetCallingGlobalContext()932 Handle<Context> Isolate::GetCallingGlobalContext() {
933 JavaScriptFrameIterator it;
934 #ifdef ENABLE_DEBUGGER_SUPPORT
935 if (debug_->InDebugger()) {
936 while (!it.done()) {
937 JavaScriptFrame* frame = it.frame();
938 Context* context = Context::cast(frame->context());
939 if (context->global_context() == *debug_->debug_context()) {
940 it.Advance();
941 } else {
942 break;
943 }
944 }
945 }
946 #endif // ENABLE_DEBUGGER_SUPPORT
947 if (it.done()) return Handle<Context>::null();
948 JavaScriptFrame* frame = it.frame();
949 Context* context = Context::cast(frame->context());
950 return Handle<Context>(context->global_context());
951 }
952
953
ArchiveThread(char * to)954 char* Isolate::ArchiveThread(char* to) {
955 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
956 RuntimeProfiler::IsolateExitedJS(this);
957 }
958 memcpy(to, reinterpret_cast<char*>(thread_local_top()),
959 sizeof(ThreadLocalTop));
960 InitializeThreadLocal();
961 return to + sizeof(ThreadLocalTop);
962 }
963
964
RestoreThread(char * from)965 char* Isolate::RestoreThread(char* from) {
966 memcpy(reinterpret_cast<char*>(thread_local_top()), from,
967 sizeof(ThreadLocalTop));
968 // This might be just paranoia, but it seems to be needed in case a
969 // thread_local_top_ is restored on a separate OS thread.
970 #ifdef USE_SIMULATOR
971 #ifdef V8_TARGET_ARCH_ARM
972 thread_local_top()->simulator_ = Simulator::current(this);
973 #elif V8_TARGET_ARCH_MIPS
974 thread_local_top()->simulator_ = Simulator::current(this);
975 #endif
976 #endif
977 if (RuntimeProfiler::IsEnabled() && current_vm_state() == JS) {
978 RuntimeProfiler::IsolateEnteredJS(this);
979 }
980 return from + sizeof(ThreadLocalTop);
981 }
982
983 } } // namespace v8::internal
984