Home | History | Annotate | Download | only in src
      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 
     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 
     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 
     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 
     93 v8::TryCatch* ThreadLocalTop::TryCatchHandler() {
     94   return TRY_CATCH_FROM_ADDRESS(try_catch_handler_address());
     95 }
     96 
     97 
     98 Address Isolate::get_address_from_id(Isolate::AddressId id) {
     99   return isolate_addresses_[id];
    100 }
    101 
    102 
    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 
    110 void Isolate::IterateThread(ThreadVisitor* v) {
    111   v->VisitThread(this, thread_local_top());
    112 }
    113 
    114 
    115 void Isolate::IterateThread(ThreadVisitor* v, char* t) {
    116   ThreadLocalTop* thread = reinterpret_cast<ThreadLocalTop*>(t);
    117   v->VisitThread(this, thread);
    118 }
    119 
    120 
    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 
    153 void Isolate::Iterate(ObjectVisitor* v) {
    154   ThreadLocalTop* current_t = thread_local_top();
    155   Iterate(v, current_t);
    156 }
    157 
    158 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    390 void Isolate::SetFailedAccessCheckCallback(
    391     v8::FailedAccessCheckCallback callback) {
    392   thread_local_top()->failed_access_check_callback_ = callback;
    393 }
    394 
    395 
    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 
    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 
    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 
    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 
    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 
    559 Failure* Isolate::TerminateExecution() {
    560   DoThrow(heap_.termination_exception(), NULL);
    561   return Failure::Exception();
    562 }
    563 
    564 
    565 Failure* Isolate::Throw(Object* exception, MessageLocation* location) {
    566   DoThrow(exception, location);
    567   return Failure::Exception();
    568 }
    569 
    570 
    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 
    585 Failure* Isolate::ThrowIllegalOperation() {
    586   return Throw(heap_.illegal_access_symbol());
    587 }
    588 
    589 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    848 void Isolate::TraceException(bool flag) {
    849   FLAG_trace_exception = flag;  // TODO(isolates): This is an unfortunate use.
    850 }
    851 
    852 
    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 
    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 
    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 
    926 Handle<Context> Isolate::global_context() {
    927   GlobalObject* global = thread_local_top()->context_->global();
    928   return Handle<Context>(global->global_context());
    929 }
    930 
    931 
    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 
    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 
    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