• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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