LCOV - code coverage report
Current view: top level - src - messages.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 452 485 93.2 %
Date: 2019-04-17 Functions: 67 74 90.5 %

          Line data    Source code
       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/messages.h"
       6             : 
       7             : #include <memory>
       8             : 
       9             : #include "src/api-inl.h"
      10             : #include "src/counters.h"
      11             : #include "src/execution.h"
      12             : #include "src/isolate-inl.h"
      13             : #include "src/keys.h"
      14             : #include "src/objects/foreign-inl.h"
      15             : #include "src/objects/frame-array-inl.h"
      16             : #include "src/objects/js-array-inl.h"
      17             : #include "src/objects/struct-inl.h"
      18             : #include "src/string-builder-inl.h"
      19             : #include "src/wasm/wasm-code-manager.h"
      20             : #include "src/wasm/wasm-objects.h"
      21             : 
      22             : namespace v8 {
      23             : namespace internal {
      24             : 
      25      396992 : MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
      26             :                                  int end_pos)
      27      793984 :     : script_(script), start_pos_(start_pos), end_pos_(end_pos) {}
      28      979254 : MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
      29             :                                  int end_pos, Handle<SharedFunctionInfo> shared)
      30             :     : script_(script),
      31             :       start_pos_(start_pos),
      32             :       end_pos_(end_pos),
      33      979254 :       shared_(shared) {}
      34     8201994 : MessageLocation::MessageLocation() : start_pos_(-1), end_pos_(-1) {}
      35             : 
      36             : // If no message listeners have been registered this one is called
      37             : // by default.
      38        1343 : void MessageHandler::DefaultMessageReport(Isolate* isolate,
      39             :                                           const MessageLocation* loc,
      40             :                                           Handle<Object> message_obj) {
      41        1343 :   std::unique_ptr<char[]> str = GetLocalizedMessage(isolate, message_obj);
      42        1343 :   if (loc == nullptr) {
      43           0 :     PrintF("%s\n", str.get());
      44             :   } else {
      45             :     HandleScope scope(isolate);
      46             :     Handle<Object> data(loc->script()->name(), isolate);
      47             :     std::unique_ptr<char[]> data_str;
      48        1343 :     if (data->IsString())
      49           0 :       data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
      50        1343 :     PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
      51        1343 :            loc->start_pos(), str.get());
      52             :   }
      53        1343 : }
      54             : 
      55     1363628 : Handle<JSMessageObject> MessageHandler::MakeMessageObject(
      56             :     Isolate* isolate, MessageTemplate message, const MessageLocation* location,
      57             :     Handle<Object> argument, Handle<FixedArray> stack_frames) {
      58             :   Factory* factory = isolate->factory();
      59             : 
      60             :   int start = -1;
      61             :   int end = -1;
      62     1363628 :   Handle<Script> script_handle = isolate->factory()->empty_script();
      63     1363628 :   if (location != nullptr) {
      64             :     start = location->start_pos();
      65             :     end = location->end_pos();
      66     1359711 :     script_handle = location->script();
      67             :   }
      68             : 
      69             :   Handle<Object> stack_frames_handle = stack_frames.is_null()
      70             :       ? Handle<Object>::cast(factory->undefined_value())
      71     2726804 :       : Handle<Object>::cast(stack_frames);
      72             : 
      73             :   Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
      74     1363628 :       message, argument, start, end, script_handle, stack_frames_handle);
      75             : 
      76     1363628 :   return message_obj;
      77             : }
      78             : 
      79        8752 : void MessageHandler::ReportMessage(Isolate* isolate, const MessageLocation* loc,
      80             :                                    Handle<JSMessageObject> message) {
      81             :   v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
      82             : 
      83        8752 :   if (api_message_obj->ErrorLevel() == v8::Isolate::kMessageError) {
      84             :     // We are calling into embedder's code which can throw exceptions.
      85             :     // Thus we need to save current exception state, reset it to the clean one
      86             :     // and ignore scheduled exceptions callbacks can throw.
      87             : 
      88             :     // We pass the exception object into the message handler callback though.
      89             :     Object exception_object = ReadOnlyRoots(isolate).undefined_value();
      90        8112 :     if (isolate->has_pending_exception()) {
      91             :       exception_object = isolate->pending_exception();
      92             :     }
      93             :     Handle<Object> exception(exception_object, isolate);
      94             : 
      95        8112 :     Isolate::ExceptionScope exception_scope(isolate);
      96             :     isolate->clear_pending_exception();
      97             :     isolate->set_external_caught_exception(false);
      98             : 
      99             :     // Turn the exception on the message into a string if it is an object.
     100        8112 :     if (message->argument()->IsJSObject()) {
     101             :       HandleScope scope(isolate);
     102             :       Handle<Object> argument(message->argument(), isolate);
     103             : 
     104             :       MaybeHandle<Object> maybe_stringified;
     105             :       Handle<Object> stringified;
     106             :       // Make sure we don't leak uncaught internally generated Error objects.
     107        4064 :       if (argument->IsJSError()) {
     108        3978 :         maybe_stringified = Object::NoSideEffectsToString(isolate, argument);
     109             :       } else {
     110         172 :         v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
     111          86 :         catcher.SetVerbose(false);
     112          86 :         catcher.SetCaptureMessage(false);
     113             : 
     114          86 :         maybe_stringified = Object::ToString(isolate, argument);
     115             :       }
     116             : 
     117        4064 :       if (!maybe_stringified.ToHandle(&stringified)) {
     118             :         DCHECK(isolate->has_pending_exception());
     119             :         isolate->clear_pending_exception();
     120             :         isolate->set_external_caught_exception(false);
     121             :         stringified =
     122          10 :             isolate->factory()->NewStringFromAsciiChecked("exception");
     123             :       }
     124        4064 :       message->set_argument(*stringified);
     125             :     }
     126             : 
     127        8112 :     v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception);
     128        8112 :     ReportMessageNoExceptions(isolate, loc, message, api_exception_obj);
     129             :   } else {
     130         640 :     ReportMessageNoExceptions(isolate, loc, message, v8::Local<v8::Value>());
     131             :   }
     132        8752 : }
     133             : 
     134        8752 : void MessageHandler::ReportMessageNoExceptions(
     135             :     Isolate* isolate, const MessageLocation* loc, Handle<Object> message,
     136             :     v8::Local<v8::Value> api_exception_obj) {
     137             :   v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
     138        8752 :   int error_level = api_message_obj->ErrorLevel();
     139             : 
     140             :   Handle<TemplateList> global_listeners =
     141             :       isolate->factory()->message_listeners();
     142             :   int global_length = global_listeners->length();
     143        8752 :   if (global_length == 0) {
     144        1343 :     DefaultMessageReport(isolate, loc, message);
     145        1343 :     if (isolate->has_scheduled_exception()) {
     146             :       isolate->clear_scheduled_exception();
     147             :     }
     148             :   } else {
     149       14953 :     for (int i = 0; i < global_length; i++) {
     150             :       HandleScope scope(isolate);
     151        7544 :       if (global_listeners->get(i)->IsUndefined(isolate)) continue;
     152             :       FixedArray listener = FixedArray::cast(global_listeners->get(i));
     153             :       Foreign callback_obj = Foreign::cast(listener->get(0));
     154             :       int32_t message_levels =
     155             :           static_cast<int32_t>(Smi::ToInt(listener->get(2)));
     156        7378 :       if (!(message_levels & error_level)) {
     157             :         continue;
     158             :       }
     159             :       v8::MessageCallback callback =
     160             :           FUNCTION_CAST<v8::MessageCallback>(callback_obj->foreign_address());
     161             :       Handle<Object> callback_data(listener->get(1), isolate);
     162             :       {
     163             :         RuntimeCallTimerScope timer(
     164        7378 :             isolate, RuntimeCallCounterId::kMessageListenerCallback);
     165             :         // Do not allow exceptions to propagate.
     166       14756 :         v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
     167        7378 :         callback(api_message_obj, callback_data->IsUndefined(isolate)
     168             :                                       ? api_exception_obj
     169        7378 :                                       : v8::Utils::ToLocal(callback_data));
     170             :       }
     171        7378 :       if (isolate->has_scheduled_exception()) {
     172             :         isolate->clear_scheduled_exception();
     173             :       }
     174             :     }
     175             :   }
     176        8752 : }
     177             : 
     178             : 
     179        4165 : Handle<String> MessageHandler::GetMessage(Isolate* isolate,
     180             :                                           Handle<Object> data) {
     181             :   Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
     182             :   Handle<Object> arg = Handle<Object>(message->argument(), isolate);
     183        4165 :   return MessageFormatter::Format(isolate, message->type(), arg);
     184             : }
     185             : 
     186        1343 : std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
     187             :     Isolate* isolate, Handle<Object> data) {
     188             :   HandleScope scope(isolate);
     189        4029 :   return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
     190             : }
     191             : 
     192             : namespace {
     193             : 
     194         975 : Object EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
     195         975 :   if (!script->has_eval_from_shared()) {
     196           9 :     return ReadOnlyRoots(isolate).undefined_value();
     197             :   }
     198             : 
     199             :   Handle<SharedFunctionInfo> shared(script->eval_from_shared(), isolate);
     200             :   // Find the name of the function calling eval.
     201         966 :   if (shared->Name()->BooleanValue(isolate)) {
     202         767 :     return shared->Name();
     203             :   }
     204             : 
     205         199 :   return shared->inferred_name();
     206             : }
     207             : 
     208         984 : MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
     209        1968 :   Handle<Object> sourceURL(script->GetNameOrSourceURL(), isolate);
     210         984 :   if (!sourceURL->IsUndefined(isolate)) {
     211             :     DCHECK(sourceURL->IsString());
     212           9 :     return Handle<String>::cast(sourceURL);
     213             :   }
     214             : 
     215         975 :   IncrementalStringBuilder builder(isolate);
     216             :   builder.AppendCString("eval at ");
     217             : 
     218             :   Handle<Object> eval_from_function_name =
     219         975 :       handle(EvalFromFunctionName(isolate, script), isolate);
     220         975 :   if (eval_from_function_name->BooleanValue(isolate)) {
     221             :     Handle<String> str;
     222        1534 :     ASSIGN_RETURN_ON_EXCEPTION(
     223             :         isolate, str, Object::ToString(isolate, eval_from_function_name),
     224             :         String);
     225         767 :     builder.AppendString(str);
     226             :   } else {
     227             :     builder.AppendCString("<anonymous>");
     228             :   }
     229             : 
     230         975 :   if (script->has_eval_from_shared()) {
     231             :     Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared(),
     232             :                                                 isolate);
     233        1932 :     if (eval_from_shared->script()->IsScript()) {
     234             :       Handle<Script> eval_from_script =
     235        1932 :           handle(Script::cast(eval_from_shared->script()), isolate);
     236             :       builder.AppendCString(" (");
     237         966 :       if (eval_from_script->compilation_type() ==
     238             :           Script::COMPILATION_TYPE_EVAL) {
     239             :         // Eval script originated from another eval.
     240             :         Handle<String> str;
     241         144 :         ASSIGN_RETURN_ON_EXCEPTION(
     242             :             isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
     243          72 :         builder.AppendString(str);
     244             :       } else {
     245             :         DCHECK(eval_from_script->compilation_type() !=
     246             :                Script::COMPILATION_TYPE_EVAL);
     247             :         // eval script originated from "real" source.
     248             :         Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
     249         894 :         if (eval_from_script->name()->IsString()) {
     250         894 :           builder.AppendString(Handle<String>::cast(name_obj));
     251             : 
     252             :           Script::PositionInfo info;
     253             : 
     254         894 :           if (Script::GetPositionInfo(eval_from_script,
     255             :                                       Script::GetEvalPosition(isolate, script),
     256             :                                       &info, Script::NO_OFFSET)) {
     257             :             builder.AppendCString(":");
     258             : 
     259             :             Handle<String> str = isolate->factory()->NumberToString(
     260        1788 :                 handle(Smi::FromInt(info.line + 1), isolate));
     261         894 :             builder.AppendString(str);
     262             : 
     263             :             builder.AppendCString(":");
     264             : 
     265             :             str = isolate->factory()->NumberToString(
     266        1788 :                 handle(Smi::FromInt(info.column + 1), isolate));
     267         894 :             builder.AppendString(str);
     268             :           }
     269             :         } else {
     270             :           DCHECK(!eval_from_script->name()->IsString());
     271             :           builder.AppendCString("unknown source");
     272             :         }
     273             :       }
     274             :     }
     275             :     builder.AppendCString(")");
     276             :   }
     277             : 
     278             :   Handle<String> result;
     279        1950 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
     280         975 :   return result;
     281             : }
     282             : 
     283             : }  // namespace
     284             : 
     285         921 : Handle<Object> StackFrameBase::GetEvalOrigin() {
     286         930 :   if (!HasScript()) return isolate_->factory()->undefined_value();
     287        1824 :   return FormatEvalOrigin(isolate_, GetScript()).ToHandleChecked();
     288             : }
     289             : 
     290       10770 : int StackFrameBase::GetScriptId() const {
     291       10770 :   if (!HasScript()) return kNone;
     292       21540 :   return GetScript()->id();
     293             : }
     294             : 
     295       75283 : bool StackFrameBase::IsEval() {
     296      149053 :   return HasScript() &&
     297      149053 :          GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL;
     298             : }
     299             : 
     300         723 : MaybeHandle<String> StackFrameBase::ToString() {
     301         723 :   IncrementalStringBuilder builder(isolate_);
     302         723 :   ToString(builder);
     303         723 :   return builder.Finish();
     304             : }
     305             : 
     306      458232 : void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
     307             :                                   int frame_ix) {
     308             :   DCHECK(!array->IsWasmFrame(frame_ix));
     309      458232 :   isolate_ = isolate;
     310      458232 :   receiver_ = handle(array->Receiver(frame_ix), isolate);
     311      458232 :   function_ = handle(array->Function(frame_ix), isolate);
     312      458232 :   code_ = handle(array->Code(frame_ix), isolate);
     313      458232 :   offset_ = array->Offset(frame_ix)->value();
     314             : 
     315             :   const int flags = array->Flags(frame_ix)->value();
     316      458232 :   is_constructor_ = (flags & FrameArray::kIsConstructor) != 0;
     317      458232 :   is_strict_ = (flags & FrameArray::kIsStrict) != 0;
     318      458232 :   is_async_ = (flags & FrameArray::kIsAsync) != 0;
     319      458232 :   is_promise_all_ = (flags & FrameArray::kIsPromiseAll) != 0;
     320      458232 : }
     321             : 
     322           0 : JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
     323             :                            Handle<JSFunction> function,
     324             :                            Handle<AbstractCode> code, int offset)
     325             :     : StackFrameBase(isolate),
     326             :       receiver_(receiver),
     327             :       function_(function),
     328             :       code_(code),
     329             :       offset_(offset),
     330             :       is_async_(false),
     331             :       is_constructor_(false),
     332           0 :       is_strict_(false) {}
     333             : 
     334       10718 : Handle<Object> JSStackFrame::GetFunction() const {
     335       10718 :   return Handle<Object>::cast(function_);
     336             : }
     337             : 
     338       64830 : Handle<Object> JSStackFrame::GetFileName() {
     339       64848 :   if (!HasScript()) return isolate_->factory()->null_value();
     340      129624 :   return handle(GetScript()->name(), isolate_);
     341             : }
     342             : 
     343      111070 : Handle<Object> JSStackFrame::GetFunctionName() {
     344      111070 :   Handle<String> result = JSFunction::GetName(function_);
     345      111070 :   if (result->length() != 0) return result;
     346             : 
     347       30596 :   if (HasScript() &&
     348       15289 :       GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
     349        1844 :     return isolate_->factory()->eval_string();
     350             :   }
     351       28770 :   return isolate_->factory()->null_value();
     352             : }
     353             : 
     354             : namespace {
     355             : 
     356       13419 : bool CheckMethodName(Isolate* isolate, Handle<JSReceiver> receiver,
     357             :                      Handle<Name> name, Handle<JSFunction> fun,
     358             :                      LookupIterator::Configuration config) {
     359             :   LookupIterator iter =
     360       13419 :       LookupIterator::PropertyOrElement(isolate, receiver, name, config);
     361       13419 :   if (iter.state() == LookupIterator::DATA) {
     362       23952 :     return iter.GetDataValue().is_identical_to(fun);
     363        1443 :   } else if (iter.state() == LookupIterator::ACCESSOR) {
     364         387 :     Handle<Object> accessors = iter.GetAccessors();
     365         387 :     if (accessors->IsAccessorPair()) {
     366             :       Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors);
     367         639 :       return pair->getter() == *fun || pair->setter() == *fun;
     368             :     }
     369             :   }
     370             :   return false;
     371             : }
     372             : 
     373       68710 : Handle<Object> ScriptNameOrSourceUrl(Handle<Script> script, Isolate* isolate) {
     374             :   Object name_or_url = script->source_url();
     375       68710 :   if (!name_or_url->IsString()) name_or_url = script->name();
     376       68710 :   return handle(name_or_url, isolate);
     377             : }
     378             : 
     379             : }  // namespace
     380             : 
     381       70099 : Handle<Object> JSStackFrame::GetScriptNameOrSourceUrl() {
     382       71576 :   if (!HasScript()) return isolate_->factory()->null_value();
     383       68622 :   return ScriptNameOrSourceUrl(GetScript(), isolate_);
     384             : }
     385             : 
     386        9475 : Handle<Object> JSStackFrame::GetMethodName() {
     387       18950 :   if (receiver_->IsNullOrUndefined(isolate_)) {
     388           0 :     return isolate_->factory()->null_value();
     389             :   }
     390             : 
     391             :   Handle<JSReceiver> receiver;
     392       18950 :   if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
     393             :     DCHECK(isolate_->has_pending_exception());
     394           0 :     isolate_->clear_pending_exception();
     395           0 :     isolate_->set_external_caught_exception(false);
     396           0 :     return isolate_->factory()->null_value();
     397             :   }
     398             : 
     399       28425 :   Handle<String> name(function_->shared()->Name(), isolate_);
     400             : 
     401             :   // The static initializer function is not a method, so don't add a
     402             :   // class name, just return the function name.
     403        9475 :   if (name->IsUtf8EqualTo(CStrVector("<static_fields_initializer>"), true)) {
     404          14 :     return name;
     405             :   }
     406             : 
     407             :   // ES2015 gives getters and setters name prefixes which must
     408             :   // be stripped to find the property name.
     409       28311 :   if (name->IsUtf8EqualTo(CStrVector("get "), true) ||
     410       18850 :       name->IsUtf8EqualTo(CStrVector("set "), true)) {
     411          81 :     name = isolate_->factory()->NewProperSubString(name, 4, name->length());
     412             :   }
     413        9461 :   if (CheckMethodName(isolate_, receiver, name, function_,
     414             :                       LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) {
     415        8396 :     return name;
     416             :   }
     417             : 
     418        1065 :   HandleScope outer_scope(isolate_);
     419             :   Handle<Object> result;
     420        3795 :   for (PrototypeIterator iter(isolate_, receiver, kStartAtReceiver);
     421        2730 :        !iter.IsAtEnd(); iter.Advance()) {
     422             :     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
     423        2739 :     if (!current->IsJSObject()) break;
     424             :     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
     425        2739 :     if (current_obj->IsAccessCheckNeeded()) break;
     426             :     Handle<FixedArray> keys =
     427        2739 :         KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, current_obj);
     428       10637 :     for (int i = 0; i < keys->length(); i++) {
     429        3958 :       HandleScope inner_scope(isolate_);
     430        3958 :       if (!keys->get(i)->IsName()) continue;
     431        3958 :       Handle<Name> name_key(Name::cast(keys->get(i)), isolate_);
     432        3958 :       if (!CheckMethodName(isolate_, current_obj, name_key, function_,
     433             :                            LookupIterator::OWN_SKIP_INTERCEPTOR))
     434             :         continue;
     435             :       // Return null in case of duplicates to avoid confusion.
     436         397 :       if (!result.is_null()) return isolate_->factory()->null_value();
     437         379 :       result = inner_scope.CloseAndEscape(name_key);
     438             :     }
     439             :   }
     440             : 
     441        1056 :   if (!result.is_null()) return outer_scope.CloseAndEscape(result);
     442        1372 :   return isolate_->factory()->null_value();
     443             : }
     444             : 
     445        9917 : Handle<Object> JSStackFrame::GetTypeName() {
     446             :   // TODO(jgruber): Check for strict/constructor here as in
     447             :   // CallSitePrototypeGetThis.
     448             : 
     449       19834 :   if (receiver_->IsNullOrUndefined(isolate_)) {
     450          18 :     return isolate_->factory()->null_value();
     451        9899 :   } else if (receiver_->IsJSProxy()) {
     452          18 :     return isolate_->factory()->Proxy_string();
     453             :   }
     454             : 
     455             :   Handle<JSReceiver> receiver;
     456       19780 :   if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
     457             :     DCHECK(isolate_->has_pending_exception());
     458           0 :     isolate_->clear_pending_exception();
     459           0 :     isolate_->set_external_caught_exception(false);
     460           0 :     return isolate_->factory()->null_value();
     461             :   }
     462             : 
     463        9890 :   return JSReceiver::GetConstructorName(receiver);
     464             : }
     465             : 
     466      101431 : int JSStackFrame::GetLineNumber() {
     467             :   DCHECK_LE(0, GetPosition());
     468      101431 :   if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
     469             :   return kNone;
     470             : }
     471             : 
     472       99793 : int JSStackFrame::GetColumnNumber() {
     473             :   DCHECK_LE(0, GetPosition());
     474       99793 :   if (HasScript()) {
     475       99775 :     return Script::GetColumnNumber(GetScript(), GetPosition()) + 1;
     476             :   }
     477             :   return kNone;
     478             : }
     479             : 
     480          27 : int JSStackFrame::GetPromiseIndex() const {
     481          27 :   return is_promise_all_ ? offset_ : kNone;
     482             : }
     483             : 
     484       90830 : bool JSStackFrame::IsNative() {
     485      180165 :   return HasScript() && GetScript()->type() == Script::TYPE_NATIVE;
     486             : }
     487             : 
     488       90875 : bool JSStackFrame::IsToplevel() {
     489      102265 :   return receiver_->IsJSGlobalProxy() || receiver_->IsNullOrUndefined(isolate_);
     490             : }
     491             : 
     492             : namespace {
     493             : 
     494      138588 : bool IsNonEmptyString(Handle<Object> object) {
     495      264708 :   return (object->IsString() && String::cast(*object)->length() > 0);
     496             : }
     497             : 
     498       59865 : void AppendFileLocation(Isolate* isolate, StackFrameBase* call_site,
     499             :                         IncrementalStringBuilder* builder) {
     500       59865 :   if (call_site->IsNative()) {
     501             :     builder->AppendCString("native");
     502           0 :     return;
     503             :   }
     504             : 
     505       59865 :   Handle<Object> file_name = call_site->GetScriptNameOrSourceUrl();
     506       59865 :   if (!file_name->IsString() && call_site->IsEval()) {
     507         756 :     Handle<Object> eval_origin = call_site->GetEvalOrigin();
     508             :     DCHECK(eval_origin->IsString());
     509         756 :     builder->AppendString(Handle<String>::cast(eval_origin));
     510             :     builder->AppendCString(", ");  // Expecting source position to follow.
     511             :   }
     512             : 
     513       59865 :   if (IsNonEmptyString(file_name)) {
     514       56597 :     builder->AppendString(Handle<String>::cast(file_name));
     515             :   } else {
     516             :     // Source code does not originate from a file and is not native, but we
     517             :     // can still get the source position inside the source string, e.g. in
     518             :     // an eval string.
     519             :     builder->AppendCString("<anonymous>");
     520             :   }
     521             : 
     522       59865 :   int line_number = call_site->GetLineNumber();
     523       59865 :   if (line_number != StackFrameBase::kNone) {
     524             :     builder->AppendCharacter(':');
     525             :     Handle<String> line_string = isolate->factory()->NumberToString(
     526      116776 :         handle(Smi::FromInt(line_number), isolate), isolate);
     527       58388 :     builder->AppendString(line_string);
     528             : 
     529       58388 :     int column_number = call_site->GetColumnNumber();
     530       58388 :     if (column_number != StackFrameBase::kNone) {
     531             :       builder->AppendCharacter(':');
     532             :       Handle<String> column_string = isolate->factory()->NumberToString(
     533       58388 :           handle(Smi::FromInt(column_number), isolate), isolate);
     534       58388 :       builder->AppendString(column_string);
     535             :     }
     536             :   }
     537             : }
     538             : 
     539        9290 : int StringIndexOf(Isolate* isolate, Handle<String> subject,
     540             :                   Handle<String> pattern) {
     541        9290 :   if (pattern->length() > subject->length()) return -1;
     542        6160 :   return String::IndexOf(isolate, subject, pattern, 0);
     543             : }
     544             : 
     545             : // Returns true iff
     546             : // 1. the subject ends with '.' + pattern, or
     547             : // 2. subject == pattern.
     548        8681 : bool StringEndsWithMethodName(Isolate* isolate, Handle<String> subject,
     549             :                               Handle<String> pattern) {
     550        8681 :   if (String::Equals(isolate, subject, pattern)) return true;
     551             : 
     552         379 :   FlatStringReader subject_reader(isolate, String::Flatten(isolate, subject));
     553         379 :   FlatStringReader pattern_reader(isolate, String::Flatten(isolate, pattern));
     554             : 
     555         379 :   int pattern_index = pattern_reader.length() - 1;
     556         379 :   int subject_index = subject_reader.length() - 1;
     557        6841 :   for (int i = 0; i <= pattern_reader.length(); i++) {  // Iterate over len + 1.
     558        3402 :     if (subject_index < 0) {
     559             :       return false;
     560             :     }
     561             : 
     562             :     const uc32 subject_char = subject_reader.Get(subject_index);
     563        3402 :     if (i == pattern_reader.length()) {
     564         271 :       if (subject_char != '.') return false;
     565        3131 :     } else if (subject_char != pattern_reader.Get(pattern_index)) {
     566             :       return false;
     567             :     }
     568             : 
     569        3231 :     pattern_index--;
     570        3231 :     subject_index--;
     571             :   }
     572             : 
     573             :   return true;
     574             : }
     575             : 
     576        9385 : void AppendMethodCall(Isolate* isolate, JSStackFrame* call_site,
     577             :                       IncrementalStringBuilder* builder) {
     578        9385 :   Handle<Object> type_name = call_site->GetTypeName();
     579        9385 :   Handle<Object> method_name = call_site->GetMethodName();
     580        9385 :   Handle<Object> function_name = call_site->GetFunctionName();
     581             : 
     582        9385 :   if (IsNonEmptyString(function_name)) {
     583        9290 :     Handle<String> function_string = Handle<String>::cast(function_name);
     584        9290 :     if (IsNonEmptyString(type_name)) {
     585        9290 :       Handle<String> type_string = Handle<String>::cast(type_name);
     586             :       bool starts_with_type_name =
     587        9290 :           (StringIndexOf(isolate, function_string, type_string) == 0);
     588        9290 :       if (!starts_with_type_name) {
     589        9222 :         builder->AppendString(type_string);
     590             :         builder->AppendCharacter('.');
     591             :       }
     592             :     }
     593        9290 :     builder->AppendString(function_string);
     594             : 
     595        9290 :     if (IsNonEmptyString(method_name)) {
     596        8681 :       Handle<String> method_string = Handle<String>::cast(method_name);
     597        8681 :       if (!StringEndsWithMethodName(isolate, function_string, method_string)) {
     598             :         builder->AppendCString(" [as ");
     599         171 :         builder->AppendString(method_string);
     600             :         builder->AppendCharacter(']');
     601             :       }
     602             :     }
     603             :   } else {
     604          95 :     if (IsNonEmptyString(type_name)) {
     605          95 :       builder->AppendString(Handle<String>::cast(type_name));
     606             :       builder->AppendCharacter('.');
     607             :     }
     608          95 :     if (IsNonEmptyString(method_name)) {
     609          36 :       builder->AppendString(Handle<String>::cast(method_name));
     610             :     } else {
     611             :       builder->AppendCString("<anonymous>");
     612             :     }
     613             :   }
     614        9385 : }
     615             : 
     616             : }  // namespace
     617             : 
     618       59822 : void JSStackFrame::ToString(IncrementalStringBuilder& builder) {
     619       59822 :   Handle<Object> function_name = GetFunctionName();
     620             : 
     621       59822 :   const bool is_toplevel = IsToplevel();
     622       59822 :   const bool is_async = IsAsync();
     623       59822 :   const bool is_promise_all = IsPromiseAll();
     624       59822 :   const bool is_constructor = IsConstructor();
     625       59822 :   const bool is_method_call = !(is_toplevel || is_constructor);
     626             : 
     627       59822 :   if (is_async) {
     628             :     builder.AppendCString("async ");
     629             :   }
     630       59822 :   if (is_promise_all) {
     631             :     // For `Promise.all(iterable)` frames we interpret the {offset_}
     632             :     // as the element index into `iterable` where the error occurred.
     633             :     builder.AppendCString("Promise.all (index ");
     634          45 :     Handle<String> index_string = isolate_->factory()->NumberToString(
     635          90 :         handle(Smi::FromInt(offset_), isolate_), isolate_);
     636          45 :     builder.AppendString(index_string);
     637             :     builder.AppendCString(")");
     638             :     return;
     639             :   }
     640       59777 :   if (is_method_call) {
     641        9385 :     AppendMethodCall(isolate_, this, &builder);
     642       50392 :   } else if (is_constructor) {
     643             :     builder.AppendCString("new ");
     644         707 :     if (IsNonEmptyString(function_name)) {
     645         707 :       builder.AppendString(Handle<String>::cast(function_name));
     646             :     } else {
     647             :       builder.AppendCString("<anonymous>");
     648             :     }
     649       49685 :   } else if (IsNonEmptyString(function_name)) {
     650       40336 :     builder.AppendString(Handle<String>::cast(function_name));
     651             :   } else {
     652        9349 :     AppendFileLocation(isolate_, this, &builder);
     653        9349 :     return;
     654             :   }
     655             : 
     656             :   builder.AppendCString(" (");
     657       50428 :   AppendFileLocation(isolate_, this, &builder);
     658             :   builder.AppendCString(")");
     659             : 
     660             :   return;
     661             : }
     662             : 
     663      199711 : int JSStackFrame::GetPosition() const {
     664      399422 :   Handle<SharedFunctionInfo> shared = handle(function_->shared(), isolate_);
     665      199711 :   SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate_, shared);
     666      399422 :   return code_->SourcePosition(offset_);
     667             : }
     668             : 
     669      528240 : bool JSStackFrame::HasScript() const {
     670     1056480 :   return function_->shared()->script()->IsScript();
     671             : }
     672             : 
     673      522197 : Handle<Script> JSStackFrame::GetScript() const {
     674     1566591 :   return handle(Script::cast(function_->shared()->script()), isolate_);
     675             : }
     676             : 
     677        6036 : void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
     678             :                                     int frame_ix) {
     679             :   // This function is called for compiled and interpreted wasm frames, and for
     680             :   // asm.js->wasm frames.
     681             :   DCHECK(array->IsWasmFrame(frame_ix) ||
     682             :          array->IsWasmInterpretedFrame(frame_ix) ||
     683             :          array->IsAsmJsWasmFrame(frame_ix));
     684        6036 :   isolate_ = isolate;
     685        6036 :   wasm_instance_ = handle(array->WasmInstance(frame_ix), isolate);
     686        6036 :   wasm_func_index_ = array->WasmFunctionIndex(frame_ix)->value();
     687        6036 :   if (array->IsWasmInterpretedFrame(frame_ix)) {
     688        3260 :     code_ = nullptr;
     689             :   } else {
     690             :     // The {WasmCode*} is held alive by the {GlobalWasmCodeRef}.
     691             :     auto global_wasm_code_ref =
     692        2776 :         Managed<wasm::GlobalWasmCodeRef>::cast(array->WasmCodeObject(frame_ix));
     693        2776 :     code_ = global_wasm_code_ref->get()->code();
     694             :   }
     695        6036 :   offset_ = array->Offset(frame_ix)->value();
     696        6036 : }
     697             : 
     698           0 : Handle<Object> WasmStackFrame::GetReceiver() const { return wasm_instance_; }
     699             : 
     700           0 : Handle<Object> WasmStackFrame::GetFunction() const {
     701           0 :   return handle(Smi::FromInt(wasm_func_index_), isolate_);
     702             : }
     703             : 
     704         912 : Handle<Object> WasmStackFrame::GetFunctionName() {
     705             :   Handle<Object> name;
     706             :   Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
     707         912 :                                          isolate_);
     708        1824 :   if (!WasmModuleObject::GetFunctionNameOrNull(isolate_, module_object,
     709         912 :                                                wasm_func_index_)
     710             :            .ToHandle(&name)) {
     711          16 :     name = isolate_->factory()->null_value();
     712             :   }
     713         912 :   return name;
     714             : }
     715             : 
     716         604 : void WasmStackFrame::ToString(IncrementalStringBuilder& builder) {
     717             :   Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
     718         604 :                                          isolate_);
     719             :   MaybeHandle<String> module_name =
     720         604 :       WasmModuleObject::GetModuleNameOrNull(isolate_, module_object);
     721             :   MaybeHandle<String> function_name = WasmModuleObject::GetFunctionNameOrNull(
     722         604 :       isolate_, module_object, wasm_func_index_);
     723         604 :   bool has_name = !module_name.is_null() || !function_name.is_null();
     724         604 :   if (has_name) {
     725         576 :     if (module_name.is_null()) {
     726         552 :       builder.AppendString(function_name.ToHandleChecked());
     727             :     } else {
     728          24 :       builder.AppendString(module_name.ToHandleChecked());
     729          24 :       if (!function_name.is_null()) {
     730             :         builder.AppendCString(".");
     731          12 :         builder.AppendString(function_name.ToHandleChecked());
     732             :       }
     733             :     }
     734             :     builder.AppendCString(" (");
     735             :   }
     736             : 
     737             :   builder.AppendCString("wasm-function[");
     738             : 
     739             :   char buffer[16];
     740         604 :   SNPrintF(ArrayVector(buffer), "%u]", wasm_func_index_);
     741             :   builder.AppendCString(buffer);
     742             : 
     743         604 :   SNPrintF(ArrayVector(buffer), ":%d", GetPosition());
     744             :   builder.AppendCString(buffer);
     745             : 
     746         604 :   if (has_name) builder.AppendCString(")");
     747             : 
     748         604 :   return;
     749             : }
     750             : 
     751        1252 : int WasmStackFrame::GetPosition() const {
     752             :   return IsInterpreted()
     753             :              ? offset_
     754             :              : FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
     755        1252 :                    code_, offset_);
     756             : }
     757             : 
     758           0 : Handle<Object> WasmStackFrame::Null() const {
     759         968 :   return isolate_->factory()->null_value();
     760             : }
     761             : 
     762        1024 : bool WasmStackFrame::HasScript() const { return true; }
     763             : 
     764        1024 : Handle<Script> WasmStackFrame::GetScript() const {
     765        2048 :   return handle(wasm_instance_->module_object()->script(), isolate_);
     766             : }
     767             : 
     768        1256 : void AsmJsWasmStackFrame::FromFrameArray(Isolate* isolate,
     769             :                                          Handle<FrameArray> array,
     770             :                                          int frame_ix) {
     771             :   DCHECK(array->IsAsmJsWasmFrame(frame_ix));
     772        1256 :   WasmStackFrame::FromFrameArray(isolate, array, frame_ix);
     773             :   is_at_number_conversion_ =
     774        1256 :       array->Flags(frame_ix)->value() & FrameArray::kAsmJsAtNumberConversion;
     775        1256 : }
     776             : 
     777         208 : Handle<Object> AsmJsWasmStackFrame::GetReceiver() const {
     778         208 :   return isolate_->global_proxy();
     779             : }
     780             : 
     781           0 : Handle<Object> AsmJsWasmStackFrame::GetFunction() const {
     782             :   // TODO(clemensh): Return lazily created JSFunction.
     783           0 :   return Null();
     784             : }
     785             : 
     786         224 : Handle<Object> AsmJsWasmStackFrame::GetFileName() {
     787         224 :   Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
     788             :   DCHECK(script->IsUserJavaScript());
     789         448 :   return handle(script->name(), isolate_);
     790             : }
     791             : 
     792          88 : Handle<Object> AsmJsWasmStackFrame::GetScriptNameOrSourceUrl() {
     793          88 :   Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
     794             :   DCHECK_EQ(Script::TYPE_NORMAL, script->type());
     795          88 :   return ScriptNameOrSourceUrl(script, isolate_);
     796             : }
     797             : 
     798         656 : int AsmJsWasmStackFrame::GetPosition() const {
     799             :   DCHECK_LE(0, offset_);
     800             :   int byte_offset =
     801         656 :       FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(code_,
     802        1312 :                                                                     offset_);
     803             :   Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
     804         656 :                                          isolate_);
     805             :   DCHECK_LE(0, byte_offset);
     806         656 :   return WasmModuleObject::GetSourcePosition(module_object, wasm_func_index_,
     807             :                                              static_cast<uint32_t>(byte_offset),
     808        1312 :                                              is_at_number_conversion_);
     809             : }
     810             : 
     811         312 : int AsmJsWasmStackFrame::GetLineNumber() {
     812             :   DCHECK_LE(0, GetPosition());
     813         312 :   Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
     814             :   DCHECK(script->IsUserJavaScript());
     815         312 :   return Script::GetLineNumber(script, GetPosition()) + 1;
     816             : }
     817             : 
     818         344 : int AsmJsWasmStackFrame::GetColumnNumber() {
     819             :   DCHECK_LE(0, GetPosition());
     820         344 :   Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
     821             :   DCHECK(script->IsUserJavaScript());
     822         344 :   return Script::GetColumnNumber(script, GetPosition()) + 1;
     823             : }
     824             : 
     825          88 : void AsmJsWasmStackFrame::ToString(IncrementalStringBuilder& builder) {
     826             :   // The string should look exactly as the respective javascript frame string.
     827             :   // Keep this method in line to
     828             :   // JSStackFrame::ToString(IncrementalStringBuilder&).
     829          88 :   Handle<Object> function_name = GetFunctionName();
     830             : 
     831          88 :   if (IsNonEmptyString(function_name)) {
     832          88 :     builder.AppendString(Handle<String>::cast(function_name));
     833             :     builder.AppendCString(" (");
     834             :   }
     835             : 
     836          88 :   AppendFileLocation(isolate_, this, &builder);
     837             : 
     838          88 :   if (IsNonEmptyString(function_name)) builder.AppendCString(")");
     839             : 
     840          88 :   return;
     841             : }
     842             : 
     843      318765 : FrameArrayIterator::FrameArrayIterator(Isolate* isolate,
     844             :                                        Handle<FrameArray> array, int frame_ix)
     845      647397 :     : isolate_(isolate), array_(array), frame_ix_(frame_ix) {}
     846             : 
     847           0 : bool FrameArrayIterator::HasFrame() const {
     848       69658 :   return (frame_ix_ < array_->FrameCount());
     849             : }
     850             : 
     851       59791 : void FrameArrayIterator::Advance() { frame_ix_++; }
     852             : 
     853      464268 : StackFrameBase* FrameArrayIterator::Frame() {
     854             :   DCHECK(HasFrame());
     855      464268 :   const int flags = array_->Flags(frame_ix_)->value();
     856             :   int flag_mask = FrameArray::kIsWasmFrame |
     857             :                   FrameArray::kIsWasmInterpretedFrame |
     858             :                   FrameArray::kIsAsmJsWasmFrame;
     859      464268 :   switch (flags & flag_mask) {
     860             :     case 0:
     861             :       // JavaScript Frame.
     862      458232 :       js_frame_.FromFrameArray(isolate_, array_, frame_ix_);
     863      458232 :       return &js_frame_;
     864             :     case FrameArray::kIsWasmFrame:
     865             :     case FrameArray::kIsWasmInterpretedFrame:
     866             :       // Wasm Frame:
     867        4780 :       wasm_frame_.FromFrameArray(isolate_, array_, frame_ix_);
     868        4780 :       return &wasm_frame_;
     869             :     case FrameArray::kIsAsmJsWasmFrame:
     870             :       // Asm.js Wasm Frame:
     871        1256 :       asm_wasm_frame_.FromFrameArray(isolate_, array_, frame_ix_);
     872        1256 :       return &asm_wasm_frame_;
     873             :     default:
     874           0 :       UNREACHABLE();
     875             :   }
     876             : }
     877             : 
     878             : namespace {
     879             : 
     880       49135 : MaybeHandle<Object> ConstructCallSite(Isolate* isolate,
     881             :                                       Handle<FrameArray> frame_array,
     882             :                                       int frame_index) {
     883             :   Handle<JSFunction> target =
     884      147405 :       handle(isolate->native_context()->callsite_function(), isolate);
     885             : 
     886             :   Handle<JSObject> obj;
     887       98270 :   ASSIGN_RETURN_ON_EXCEPTION(
     888             :       isolate, obj,
     889             :       JSObject::New(target, target, Handle<AllocationSite>::null()), Object);
     890             : 
     891             :   Handle<Symbol> key = isolate->factory()->call_site_frame_array_symbol();
     892       98270 :   RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
     893             :                                    obj, key, frame_array, DONT_ENUM),
     894             :                       Object);
     895             : 
     896             :   key = isolate->factory()->call_site_frame_index_symbol();
     897             :   Handle<Object> value(Smi::FromInt(frame_index), isolate);
     898       98270 :   RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
     899             :                                    obj, key, value, DONT_ENUM),
     900             :                       Object);
     901             : 
     902       49135 :   return obj;
     903             : }
     904             : 
     905             : // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into
     906             : // a JSArray of JSCallSite objects.
     907        5468 : MaybeHandle<JSArray> GetStackFrames(Isolate* isolate,
     908             :                                     Handle<FrameArray> elems) {
     909             :   const int frame_count = elems->FrameCount();
     910             : 
     911        5468 :   Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count);
     912      103738 :   for (int i = 0; i < frame_count; i++) {
     913             :     Handle<Object> site;
     914       98270 :     ASSIGN_RETURN_ON_EXCEPTION(isolate, site,
     915             :                                ConstructCallSite(isolate, elems, i), JSArray);
     916       49135 :     frames->set(i, *site);
     917             :   }
     918             : 
     919        5468 :   return isolate->factory()->NewJSArrayWithElements(frames);
     920             : }
     921             : 
     922        9867 : MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
     923             :                                       IncrementalStringBuilder* builder) {
     924             :   MaybeHandle<String> err_str =
     925        9867 :       ErrorUtils::ToString(isolate, Handle<Object>::cast(error));
     926        9867 :   if (err_str.is_null()) {
     927             :     // Error.toString threw. Try to return a string representation of the thrown
     928             :     // exception instead.
     929             : 
     930             :     DCHECK(isolate->has_pending_exception());
     931             :     Handle<Object> pending_exception =
     932           0 :         handle(isolate->pending_exception(), isolate);
     933             :     isolate->clear_pending_exception();
     934             :     isolate->set_external_caught_exception(false);
     935             : 
     936           0 :     err_str = ErrorUtils::ToString(isolate, pending_exception);
     937           0 :     if (err_str.is_null()) {
     938             :       // Formatting the thrown exception threw again, give up.
     939             :       DCHECK(isolate->has_pending_exception());
     940             :       isolate->clear_pending_exception();
     941             :       isolate->set_external_caught_exception(false);
     942             :       builder->AppendCString("<error>");
     943             :     } else {
     944             :       // Formatted thrown exception successfully, append it.
     945             :       builder->AppendCString("<error: ");
     946           0 :       builder->AppendString(err_str.ToHandleChecked());
     947             :       builder->AppendCharacter('>');
     948             :     }
     949             :   } else {
     950        9867 :     builder->AppendString(err_str.ToHandleChecked());
     951             :   }
     952             : 
     953        9867 :   return error;
     954             : }
     955             : 
     956             : class PrepareStackTraceScope {
     957             :  public:
     958             :   explicit PrepareStackTraceScope(Isolate* isolate) : isolate_(isolate) {
     959             :     DCHECK(!isolate_->formatting_stack_trace());
     960             :     isolate_->set_formatting_stack_trace(true);
     961             :   }
     962             : 
     963             :   ~PrepareStackTraceScope() { isolate_->set_formatting_stack_trace(false); }
     964             : 
     965             :  private:
     966             :   Isolate* isolate_;
     967             : 
     968             :   DISALLOW_COPY_AND_ASSIGN(PrepareStackTraceScope);
     969             : };
     970             : 
     971             : }  // namespace
     972             : 
     973             : // static
     974       15335 : MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
     975             :                                                  Handle<JSObject> error,
     976             :                                                  Handle<Object> raw_stack) {
     977             :   DCHECK(raw_stack->IsFixedArray());
     978             :   Handle<FrameArray> elems = Handle<FrameArray>::cast(raw_stack);
     979             : 
     980             :   const bool in_recursion = isolate->formatting_stack_trace();
     981       15335 :   if (!in_recursion) {
     982       15290 :     if (isolate->HasPrepareStackTraceCallback()) {
     983          24 :       Handle<Context> error_context = error->GetCreationContext();
     984             :       DCHECK(!error_context.is_null() && error_context->IsNativeContext());
     985             :       PrepareStackTraceScope scope(isolate);
     986             : 
     987             :       Handle<JSArray> sites;
     988          24 :       ASSIGN_RETURN_ON_EXCEPTION(isolate, sites, GetStackFrames(isolate, elems),
     989             :                                  Object);
     990             : 
     991             :       Handle<Object> result;
     992          24 :       ASSIGN_RETURN_ON_EXCEPTION(
     993             :           isolate, result,
     994             :           isolate->RunPrepareStackTraceCallback(error_context, error, sites),
     995             :           Object);
     996           6 :       return result;
     997             :     } else {
     998       15278 :       Handle<JSFunction> global_error = isolate->error_function();
     999             : 
    1000             :       // If there's a user-specified "prepareStackTrace" function, call it on
    1001             :       // the frames and use its result.
    1002             : 
    1003             :       Handle<Object> prepare_stack_trace;
    1004       30556 :       ASSIGN_RETURN_ON_EXCEPTION(
    1005             :           isolate, prepare_stack_trace,
    1006             :           JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"),
    1007             :           Object);
    1008             : 
    1009       15278 :       if (prepare_stack_trace->IsJSFunction()) {
    1010             :         PrepareStackTraceScope scope(isolate);
    1011             : 
    1012        5456 :         isolate->CountUsage(v8::Isolate::kErrorPrepareStackTrace);
    1013             : 
    1014             :         Handle<JSArray> sites;
    1015       10912 :         ASSIGN_RETURN_ON_EXCEPTION(isolate, sites,
    1016             :                                    GetStackFrames(isolate, elems), Object);
    1017             : 
    1018             :         const int argc = 2;
    1019             :         ScopedVector<Handle<Object>> argv(argc);
    1020        5456 :         argv[0] = error;
    1021        5456 :         argv[1] = sites;
    1022             : 
    1023             :         Handle<Object> result;
    1024             : 
    1025       10912 :         ASSIGN_RETURN_ON_EXCEPTION(
    1026             :             isolate, result,
    1027             :             Execution::Call(isolate, prepare_stack_trace, global_error, argc,
    1028             :                             argv.start()),
    1029             :             Object);
    1030             : 
    1031        5346 :         return result;
    1032             :       }
    1033             :     }
    1034             :   }
    1035             : 
    1036             :   // Otherwise, run our internal formatting logic.
    1037             : 
    1038        9867 :   IncrementalStringBuilder builder(isolate);
    1039             : 
    1040       19734 :   RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder),
    1041             :                       Object);
    1042             : 
    1043       19734 :   wasm::WasmCodeRefScope wasm_code_ref_scope;
    1044             : 
    1045       69658 :   for (FrameArrayIterator it(isolate, elems); it.HasFrame(); it.Advance()) {
    1046             :     builder.AppendCString("\n    at ");
    1047             : 
    1048       59791 :     StackFrameBase* frame = it.Frame();
    1049       59791 :     frame->ToString(builder);
    1050       59791 :     if (isolate->has_pending_exception()) {
    1051             :       // CallSite.toString threw. Parts of the current frame might have been
    1052             :       // stringified already regardless. Still, try to append a string
    1053             :       // representation of the thrown exception.
    1054             : 
    1055             :       Handle<Object> pending_exception =
    1056           0 :           handle(isolate->pending_exception(), isolate);
    1057             :       isolate->clear_pending_exception();
    1058             :       isolate->set_external_caught_exception(false);
    1059             : 
    1060             :       MaybeHandle<String> exception_string =
    1061           0 :           ErrorUtils::ToString(isolate, pending_exception);
    1062           0 :       if (exception_string.is_null()) {
    1063             :         // Formatting the thrown exception threw again, give up.
    1064             : 
    1065             :         builder.AppendCString("<error>");
    1066             :       } else {
    1067             :         // Formatted thrown exception successfully, append it.
    1068             :         builder.AppendCString("<error: ");
    1069           0 :         builder.AppendString(exception_string.ToHandleChecked());
    1070             :         builder.AppendCString("<error>");
    1071             :       }
    1072             :     }
    1073             :   }
    1074             : 
    1075        9867 :   return builder.Finish();
    1076             : }
    1077             : 
    1078        7219 : Handle<String> MessageFormatter::Format(Isolate* isolate, MessageTemplate index,
    1079             :                                         Handle<Object> arg) {
    1080             :   Factory* factory = isolate->factory();
    1081        7219 :   Handle<String> result_string = Object::NoSideEffectsToString(isolate, arg);
    1082             :   MaybeHandle<String> maybe_result_string = MessageFormatter::Format(
    1083             :       isolate, index, result_string, factory->empty_string(),
    1084        7219 :       factory->empty_string());
    1085        7219 :   if (!maybe_result_string.ToHandle(&result_string)) {
    1086             :     DCHECK(isolate->has_pending_exception());
    1087             :     isolate->clear_pending_exception();
    1088           0 :     return factory->InternalizeOneByteString(StaticCharVector("<error>"));
    1089             :   }
    1090             :   // A string that has been obtained from JS code in this way is
    1091             :   // likely to be a complicated ConsString of some sort.  We flatten it
    1092             :   // here to improve the efficiency of converting it to a C string and
    1093             :   // other operations that are likely to take place (see GetLocalizedMessage
    1094             :   // for example).
    1095        7219 :   return String::Flatten(isolate, result_string);
    1096             : }
    1097             : 
    1098     1212263 : const char* MessageFormatter::TemplateString(MessageTemplate index) {
    1099     1212263 :   switch (index) {
    1100             : #define CASE(NAME, STRING)       \
    1101             :   case MessageTemplate::k##NAME: \
    1102             :     return STRING;
    1103          60 :     MESSAGE_TEMPLATES(CASE)
    1104             : #undef CASE
    1105             :     case MessageTemplate::kLastMessage:
    1106             :     default:
    1107           0 :       return nullptr;
    1108             :   }
    1109             : }
    1110             : 
    1111     1163518 : MaybeHandle<String> MessageFormatter::Format(Isolate* isolate,
    1112             :                                              MessageTemplate index,
    1113             :                                              Handle<String> arg0,
    1114             :                                              Handle<String> arg1,
    1115             :                                              Handle<String> arg2) {
    1116     1163518 :   const char* template_string = TemplateString(index);
    1117     1163518 :   if (template_string == nullptr) {
    1118           0 :     isolate->ThrowIllegalOperation();
    1119           0 :     return MaybeHandle<String>();
    1120             :   }
    1121             : 
    1122     1163518 :   IncrementalStringBuilder builder(isolate);
    1123             : 
    1124             :   unsigned int i = 0;
    1125     1163518 :   Handle<String> args[] = {arg0, arg1, arg2};
    1126    83175898 :   for (const char* c = template_string; *c != '\0'; c++) {
    1127    41006190 :     if (*c == '%') {
    1128             :       // %% results in verbatim %.
    1129      756417 :       if (*(c + 1) == '%') {
    1130           0 :         c++;
    1131             :         builder.AppendCharacter('%');
    1132             :       } else {
    1133             :         DCHECK(i < arraysize(args));
    1134      756417 :         Handle<String> arg = args[i++];
    1135      756417 :         builder.AppendString(arg);
    1136             :       }
    1137             :     } else {
    1138    40249773 :       builder.AppendCharacter(*c);
    1139             :     }
    1140             :   }
    1141             : 
    1142     1163518 :   return builder.Finish();
    1143             : }
    1144             : 
    1145     1258014 : MaybeHandle<Object> ErrorUtils::Construct(
    1146             :     Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
    1147             :     Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
    1148             :     bool suppress_detailed_trace) {
    1149             :   // 1. If NewTarget is undefined, let newTarget be the active function object,
    1150             :   // else let newTarget be NewTarget.
    1151             : 
    1152             :   Handle<JSReceiver> new_target_recv =
    1153             :       new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
    1154     1258014 :                                  : Handle<JSReceiver>::cast(target);
    1155             : 
    1156             :   // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
    1157             :   //    « [[ErrorData]] »).
    1158             :   Handle<JSObject> err;
    1159     2516028 :   ASSIGN_RETURN_ON_EXCEPTION(
    1160             :       isolate, err,
    1161             :       JSObject::New(target, new_target_recv, Handle<AllocationSite>::null()),
    1162             :       Object);
    1163             : 
    1164             :   // 3. If message is not undefined, then
    1165             :   //  a. Let msg be ? ToString(message).
    1166             :   //  b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
    1167             :   //     true, [[Enumerable]]: false, [[Configurable]]: true}.
    1168             :   //  c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
    1169             :   // 4. Return O.
    1170             : 
    1171     1258014 :   if (!message->IsUndefined(isolate)) {
    1172             :     Handle<String> msg_string;
    1173     2492248 :     ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
    1174             :                                Object::ToString(isolate, message), Object);
    1175     2492230 :     RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
    1176             :                                      err, isolate->factory()->message_string(),
    1177             :                                      msg_string, DONT_ENUM),
    1178             :                         Object);
    1179             :   }
    1180             : 
    1181             :   // Optionally capture a more detailed stack trace for the message.
    1182     1258005 :   if (!suppress_detailed_trace) {
    1183     2419356 :     RETURN_ON_EXCEPTION(isolate, isolate->CaptureAndSetDetailedStackTrace(err),
    1184             :                         Object);
    1185             :   }
    1186             : 
    1187             :   // Capture a simple stack trace for the stack property.
    1188     2516010 :   RETURN_ON_EXCEPTION(isolate,
    1189             :                       isolate->CaptureAndSetSimpleStackTrace(err, mode, caller),
    1190             :                       Object);
    1191             : 
    1192     1258005 :   return err;
    1193             : }
    1194             : 
    1195             : namespace {
    1196             : 
    1197      608875 : MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
    1198             :                                                Handle<JSReceiver> recv,
    1199             :                                                Handle<String> key,
    1200             :                                                Handle<String> default_str) {
    1201             :   Handle<Object> obj;
    1202     1217750 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, obj,
    1203             :                              JSObject::GetProperty(isolate, recv, key), String);
    1204             : 
    1205             :   Handle<String> str;
    1206      603031 :   if (obj->IsUndefined(isolate)) {
    1207         162 :     str = default_str;
    1208             :   } else {
    1209     1205738 :     ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
    1210             :                                String);
    1211             :   }
    1212             : 
    1213      595156 :   return str;
    1214             : }
    1215             : 
    1216             : }  // namespace
    1217             : 
    1218             : // ES6 section 19.5.3.4 Error.prototype.toString ( )
    1219      308573 : MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
    1220             :                                          Handle<Object> receiver) {
    1221             :   // 1. Let O be the this value.
    1222             :   // 2. If Type(O) is not Object, throw a TypeError exception.
    1223      308573 :   if (!receiver->IsJSReceiver()) {
    1224             :     return isolate->Throw<String>(isolate->factory()->NewTypeError(
    1225             :         MessageTemplate::kIncompatibleMethodReceiver,
    1226             :         isolate->factory()->NewStringFromAsciiChecked(
    1227             :             "Error.prototype.toString"),
    1228         594 :         receiver));
    1229             :   }
    1230      308375 :   Handle<JSReceiver> recv = Handle<JSReceiver>::cast(receiver);
    1231             : 
    1232             :   // 3. Let name be ? Get(O, "name").
    1233             :   // 4. If name is undefined, let name be "Error"; otherwise let name be
    1234             :   // ? ToString(name).
    1235      308375 :   Handle<String> name_key = isolate->factory()->name_string();
    1236      308375 :   Handle<String> name_default = isolate->factory()->Error_string();
    1237             :   Handle<String> name;
    1238      616750 :   ASSIGN_RETURN_ON_EXCEPTION(
    1239             :       isolate, name,
    1240             :       GetStringPropertyOrDefault(isolate, recv, name_key, name_default),
    1241             :       String);
    1242             : 
    1243             :   // 5. Let msg be ? Get(O, "message").
    1244             :   // 6. If msg is undefined, let msg be the empty String; otherwise let msg be
    1245             :   // ? ToString(msg).
    1246      300500 :   Handle<String> msg_key = isolate->factory()->message_string();
    1247      300500 :   Handle<String> msg_default = isolate->factory()->empty_string();
    1248             :   Handle<String> msg;
    1249      601000 :   ASSIGN_RETURN_ON_EXCEPTION(
    1250             :       isolate, msg,
    1251             :       GetStringPropertyOrDefault(isolate, recv, msg_key, msg_default), String);
    1252             : 
    1253             :   // 7. If name is the empty String, return msg.
    1254             :   // 8. If msg is the empty String, return name.
    1255      294656 :   if (name->length() == 0) return msg;
    1256      294593 :   if (msg->length() == 0) return name;
    1257             : 
    1258             :   // 9. Return the result of concatenating name, the code unit 0x003A (COLON),
    1259             :   // the code unit 0x0020 (SPACE), and msg.
    1260      291204 :   IncrementalStringBuilder builder(isolate);
    1261      291204 :   builder.AppendString(name);
    1262             :   builder.AppendCString(": ");
    1263      291204 :   builder.AppendString(msg);
    1264             : 
    1265             :   Handle<String> result;
    1266      582408 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
    1267      291204 :   return result;
    1268             : }
    1269             : 
    1270             : namespace {
    1271             : 
    1272     1156294 : Handle<String> DoFormatMessage(Isolate* isolate, MessageTemplate index,
    1273             :                                Handle<Object> arg0, Handle<Object> arg1,
    1274             :                                Handle<Object> arg2) {
    1275     1156294 :   Handle<String> arg0_str = Object::NoSideEffectsToString(isolate, arg0);
    1276     1156294 :   Handle<String> arg1_str = Object::NoSideEffectsToString(isolate, arg1);
    1277     1156294 :   Handle<String> arg2_str = Object::NoSideEffectsToString(isolate, arg2);
    1278             : 
    1279     2312588 :   isolate->native_context()->IncrementErrorsThrown();
    1280             : 
    1281             :   Handle<String> msg;
    1282     2312588 :   if (!MessageFormatter::Format(isolate, index, arg0_str, arg1_str, arg2_str)
    1283             :            .ToHandle(&msg)) {
    1284             :     DCHECK(isolate->has_pending_exception());
    1285             :     isolate->clear_pending_exception();
    1286             :     isolate->set_external_caught_exception(false);
    1287          18 :     return isolate->factory()->NewStringFromAsciiChecked("<error>");
    1288             :   }
    1289             : 
    1290     1156276 :   return msg;
    1291             : }
    1292             : 
    1293             : }  // namespace
    1294             : 
    1295             : // static
    1296     1156294 : MaybeHandle<Object> ErrorUtils::MakeGenericError(
    1297             :     Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
    1298             :     Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
    1299             :     FrameSkipMode mode) {
    1300     1156294 :   if (FLAG_clear_exceptions_on_js_entry) {
    1301             :     // This function used to be implemented in JavaScript, and JSEntry
    1302             :     // clears any pending exceptions - so whenever we'd call this from C++,
    1303             :     // pending exceptions would be cleared. Preserve this behavior.
    1304             :     isolate->clear_pending_exception();
    1305             :   }
    1306             : 
    1307             :   DCHECK(mode != SKIP_UNTIL_SEEN);
    1308             : 
    1309             :   Handle<Object> no_caller;
    1310     1156294 :   Handle<String> msg = DoFormatMessage(isolate, index, arg0, arg1, arg2);
    1311             :   return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode,
    1312     1156294 :                                no_caller, false);
    1313             : }
    1314             : 
    1315             : }  // namespace internal
    1316      121996 : }  // namespace v8

Generated by: LCOV version 1.10