Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/v8.h"
      6 
      7 #include "src/api.h"
      8 #include "src/execution.h"
      9 #include "src/heap/spaces-inl.h"
     10 #include "src/messages.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 
     16 // If no message listeners have been registered this one is called
     17 // by default.
     18 void MessageHandler::DefaultMessageReport(Isolate* isolate,
     19                                           const MessageLocation* loc,
     20                                           Handle<Object> message_obj) {
     21   SmartArrayPointer<char> str = GetLocalizedMessage(isolate, message_obj);
     22   if (loc == NULL) {
     23     PrintF("%s\n", str.get());
     24   } else {
     25     HandleScope scope(isolate);
     26     Handle<Object> data(loc->script()->name(), isolate);
     27     SmartArrayPointer<char> data_str;
     28     if (data->IsString())
     29       data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
     30     PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
     31            loc->start_pos(), str.get());
     32   }
     33 }
     34 
     35 
     36 Handle<JSMessageObject> MessageHandler::MakeMessageObject(
     37     Isolate* isolate,
     38     const char* type,
     39     MessageLocation* loc,
     40     Vector< Handle<Object> > args,
     41     Handle<JSArray> stack_frames) {
     42   Factory* factory = isolate->factory();
     43   Handle<String> type_handle = factory->InternalizeUtf8String(type);
     44   Handle<FixedArray> arguments_elements =
     45       factory->NewFixedArray(args.length());
     46   for (int i = 0; i < args.length(); i++) {
     47     arguments_elements->set(i, *args[i]);
     48   }
     49   Handle<JSArray> arguments_handle =
     50       factory->NewJSArrayWithElements(arguments_elements);
     51 
     52   int start = 0;
     53   int end = 0;
     54   Handle<Object> script_handle = factory->undefined_value();
     55   if (loc) {
     56     start = loc->start_pos();
     57     end = loc->end_pos();
     58     script_handle = Script::GetWrapper(loc->script());
     59   }
     60 
     61   Handle<Object> stack_frames_handle = stack_frames.is_null()
     62       ? Handle<Object>::cast(factory->undefined_value())
     63       : Handle<Object>::cast(stack_frames);
     64 
     65   Handle<JSMessageObject> message =
     66       factory->NewJSMessageObject(type_handle,
     67                                   arguments_handle,
     68                                   start,
     69                                   end,
     70                                   script_handle,
     71                                   stack_frames_handle);
     72 
     73   return message;
     74 }
     75 
     76 
     77 void MessageHandler::ReportMessage(Isolate* isolate,
     78                                    MessageLocation* loc,
     79                                    Handle<Object> message) {
     80   // We are calling into embedder's code which can throw exceptions.
     81   // Thus we need to save current exception state, reset it to the clean one
     82   // and ignore scheduled exceptions callbacks can throw.
     83 
     84   // We pass the exception object into the message handler callback though.
     85   Object* exception_object = isolate->heap()->undefined_value();
     86   if (isolate->has_pending_exception()) {
     87     exception_object = isolate->pending_exception();
     88   }
     89   Handle<Object> exception_handle(exception_object, isolate);
     90 
     91   Isolate::ExceptionScope exception_scope(isolate);
     92   isolate->clear_pending_exception();
     93   isolate->set_external_caught_exception(false);
     94 
     95   v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
     96   v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception_handle);
     97 
     98   v8::NeanderArray global_listeners(isolate->factory()->message_listeners());
     99   int global_length = global_listeners.length();
    100   if (global_length == 0) {
    101     DefaultMessageReport(isolate, loc, message);
    102     if (isolate->has_scheduled_exception()) {
    103       isolate->clear_scheduled_exception();
    104     }
    105   } else {
    106     for (int i = 0; i < global_length; i++) {
    107       HandleScope scope(isolate);
    108       if (global_listeners.get(i)->IsUndefined()) continue;
    109       v8::NeanderObject listener(JSObject::cast(global_listeners.get(i)));
    110       Handle<Foreign> callback_obj(Foreign::cast(listener.get(0)));
    111       v8::MessageCallback callback =
    112           FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
    113       Handle<Object> callback_data(listener.get(1), isolate);
    114       {
    115         // Do not allow exceptions to propagate.
    116         v8::TryCatch try_catch;
    117         callback(api_message_obj, callback_data->IsUndefined()
    118                                       ? api_exception_obj
    119                                       : v8::Utils::ToLocal(callback_data));
    120       }
    121       if (isolate->has_scheduled_exception()) {
    122         isolate->clear_scheduled_exception();
    123       }
    124     }
    125   }
    126 }
    127 
    128 
    129 Handle<String> MessageHandler::GetMessage(Isolate* isolate,
    130                                           Handle<Object> data) {
    131   Factory* factory = isolate->factory();
    132   Handle<String> fmt_str =
    133       factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("FormatMessage"));
    134   Handle<JSFunction> fun = Handle<JSFunction>::cast(Object::GetProperty(
    135           isolate->js_builtins_object(), fmt_str).ToHandleChecked());
    136   Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
    137   Handle<Object> argv[] = { Handle<Object>(message->type(), isolate),
    138                             Handle<Object>(message->arguments(), isolate) };
    139 
    140   MaybeHandle<Object> maybe_result = Execution::TryCall(
    141       fun, isolate->js_builtins_object(), arraysize(argv), argv);
    142   Handle<Object> result;
    143   if (!maybe_result.ToHandle(&result) || !result->IsString()) {
    144     return factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("<error>"));
    145   }
    146   Handle<String> result_string = Handle<String>::cast(result);
    147   // A string that has been obtained from JS code in this way is
    148   // likely to be a complicated ConsString of some sort.  We flatten it
    149   // here to improve the efficiency of converting it to a C string and
    150   // other operations that are likely to take place (see GetLocalizedMessage
    151   // for example).
    152   result_string = String::Flatten(result_string);
    153   return result_string;
    154 }
    155 
    156 
    157 SmartArrayPointer<char> MessageHandler::GetLocalizedMessage(
    158     Isolate* isolate,
    159     Handle<Object> data) {
    160   HandleScope scope(isolate);
    161   return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
    162 }
    163 
    164 
    165 } }  // namespace v8::internal
    166