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/execution/messages.h"
6
7#include <memory>
8
9#include "src/api/api-inl.h"
10#include "src/ast/ast.h"
11#include "src/ast/prettyprinter.h"
12#include "src/base/v8-fallthrough.h"
13#include "src/execution/execution.h"
14#include "src/execution/frames-inl.h"
15#include "src/execution/frames.h"
16#include "src/execution/isolate-inl.h"
17#include "src/logging/runtime-call-stats-scope.h"
18#include "src/objects/call-site-info-inl.h"
19#include "src/objects/foreign-inl.h"
20#include "src/objects/js-array-inl.h"
21#include "src/objects/struct-inl.h"
22#include "src/parsing/parse-info.h"
23#include "src/parsing/parsing.h"
24#include "src/roots/roots.h"
25#include "src/strings/string-builder-inl.h"
26
27namespace v8 {
28namespace internal {
29
30MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
31                                 int end_pos)
32    : script_(script),
33      start_pos_(start_pos),
34      end_pos_(end_pos),
35      bytecode_offset_(-1) {}
36
37MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
38                                 int end_pos, Handle<SharedFunctionInfo> shared)
39    : script_(script),
40      start_pos_(start_pos),
41      end_pos_(end_pos),
42      bytecode_offset_(-1),
43      shared_(shared) {}
44
45MessageLocation::MessageLocation(Handle<Script> script,
46                                 Handle<SharedFunctionInfo> shared,
47                                 int bytecode_offset)
48    : script_(script),
49      start_pos_(-1),
50      end_pos_(-1),
51      bytecode_offset_(bytecode_offset),
52      shared_(shared) {}
53
54MessageLocation::MessageLocation()
55    : start_pos_(-1), end_pos_(-1), bytecode_offset_(-1) {}
56
57// If no message listeners have been registered this one is called
58// by default.
59void MessageHandler::DefaultMessageReport(Isolate* isolate,
60                                          const MessageLocation* loc,
61                                          Handle<Object> message_obj) {
62  std::unique_ptr<char[]> str = GetLocalizedMessage(isolate, message_obj);
63  if (loc == nullptr) {
64    PrintF("%s\n", str.get());
65  } else {
66    HandleScope scope(isolate);
67    Handle<Object> data(loc->script()->name(), isolate);
68    std::unique_ptr<char[]> data_str;
69    if (data->IsString())
70      data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
71    PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
72           loc->start_pos(), str.get());
73  }
74}
75
76Handle<JSMessageObject> MessageHandler::MakeMessageObject(
77    Isolate* isolate, MessageTemplate message, const MessageLocation* location,
78    Handle<Object> argument, Handle<FixedArray> stack_frames) {
79  Factory* factory = isolate->factory();
80
81  int start = -1;
82  int end = -1;
83  int bytecode_offset = -1;
84  Handle<Script> script_handle = isolate->factory()->empty_script();
85  Handle<SharedFunctionInfo> shared_info;
86  if (location != nullptr && !FLAG_correctness_fuzzer_suppressions) {
87    start = location->start_pos();
88    end = location->end_pos();
89    script_handle = location->script();
90    bytecode_offset = location->bytecode_offset();
91    shared_info = location->shared();
92  }
93
94  Handle<Object> stack_frames_handle =
95      stack_frames.is_null() ? Handle<Object>::cast(factory->undefined_value())
96                             : Handle<Object>::cast(stack_frames);
97
98  Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
99      message, argument, start, end, shared_info, bytecode_offset,
100      script_handle, stack_frames_handle);
101
102  return message_obj;
103}
104
105void MessageHandler::ReportMessage(Isolate* isolate, const MessageLocation* loc,
106                                   Handle<JSMessageObject> message) {
107  v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
108
109  if (api_message_obj->ErrorLevel() != v8::Isolate::kMessageError) {
110    ReportMessageNoExceptions(isolate, loc, message, v8::Local<v8::Value>());
111    return;
112  }
113
114  // We are calling into embedder's code which can throw exceptions.
115  // Thus we need to save current exception state, reset it to the clean one
116  // and ignore scheduled exceptions callbacks can throw.
117
118  // We pass the exception object into the message handler callback though.
119  Object exception_object = ReadOnlyRoots(isolate).undefined_value();
120  if (isolate->has_pending_exception()) {
121    exception_object = isolate->pending_exception();
122  }
123  Handle<Object> exception(exception_object, isolate);
124
125  Isolate::ExceptionScope exception_scope(isolate);
126  isolate->clear_pending_exception();
127  isolate->set_external_caught_exception(false);
128
129  // Turn the exception on the message into a string if it is an object.
130  if (message->argument().IsJSObject()) {
131    HandleScope scope(isolate);
132    Handle<Object> argument(message->argument(), isolate);
133
134    MaybeHandle<Object> maybe_stringified;
135    Handle<Object> stringified;
136    // Make sure we don't leak uncaught internally generated Error objects.
137    if (argument->IsJSError()) {
138      maybe_stringified = Object::NoSideEffectsToString(isolate, argument);
139    } else {
140      v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
141      catcher.SetVerbose(false);
142      catcher.SetCaptureMessage(false);
143
144      maybe_stringified = Object::ToString(isolate, argument);
145    }
146
147    if (!maybe_stringified.ToHandle(&stringified)) {
148      DCHECK(isolate->has_pending_exception());
149      isolate->clear_pending_exception();
150      isolate->set_external_caught_exception(false);
151      stringified = isolate->factory()->exception_string();
152    }
153    message->set_argument(*stringified);
154  }
155
156  v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception);
157  ReportMessageNoExceptions(isolate, loc, message, api_exception_obj);
158}
159
160void MessageHandler::ReportMessageNoExceptions(
161    Isolate* isolate, const MessageLocation* loc, Handle<Object> message,
162    v8::Local<v8::Value> api_exception_obj) {
163  v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
164  int error_level = api_message_obj->ErrorLevel();
165
166  Handle<TemplateList> global_listeners =
167      isolate->factory()->message_listeners();
168  int global_length = global_listeners->length();
169  if (global_length == 0) {
170    DefaultMessageReport(isolate, loc, message);
171    if (isolate->has_scheduled_exception()) {
172      isolate->clear_scheduled_exception();
173    }
174  } else {
175    for (int i = 0; i < global_length; i++) {
176      HandleScope scope(isolate);
177      if (global_listeners->get(i).IsUndefined(isolate)) continue;
178      FixedArray listener = FixedArray::cast(global_listeners->get(i));
179      Foreign callback_obj = Foreign::cast(listener.get(0));
180      int32_t message_levels =
181          static_cast<int32_t>(Smi::ToInt(listener.get(2)));
182      if (!(message_levels & error_level)) {
183        continue;
184      }
185      v8::MessageCallback callback =
186          FUNCTION_CAST<v8::MessageCallback>(callback_obj.foreign_address());
187      Handle<Object> callback_data(listener.get(1), isolate);
188      {
189        RCS_SCOPE(isolate, RuntimeCallCounterId::kMessageListenerCallback);
190        // Do not allow exceptions to propagate.
191        v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
192        callback(api_message_obj, callback_data->IsUndefined(isolate)
193                                      ? api_exception_obj
194                                      : v8::Utils::ToLocal(callback_data));
195      }
196      if (isolate->has_scheduled_exception()) {
197        isolate->clear_scheduled_exception();
198      }
199    }
200  }
201}
202
203Handle<String> MessageHandler::GetMessage(Isolate* isolate,
204                                          Handle<Object> data) {
205  Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
206  Handle<Object> arg = Handle<Object>(message->argument(), isolate);
207  return MessageFormatter::Format(isolate, message->type(), arg);
208}
209
210std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
211    Isolate* isolate, Handle<Object> data) {
212  HandleScope scope(isolate);
213  return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
214}
215
216namespace {
217
218// Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into
219// a JSArray of JSCallSite objects.
220MaybeHandle<JSArray> GetStackFrames(Isolate* isolate,
221                                    Handle<FixedArray> frames) {
222  int frame_count = frames->length();
223  Handle<JSFunction> constructor = isolate->callsite_function();
224  Handle<FixedArray> sites = isolate->factory()->NewFixedArray(frame_count);
225  for (int i = 0; i < frame_count; ++i) {
226    Handle<CallSiteInfo> frame(CallSiteInfo::cast(frames->get(i)), isolate);
227    Handle<JSObject> site;
228    ASSIGN_RETURN_ON_EXCEPTION(
229        isolate, site,
230        JSObject::New(constructor, constructor, Handle<AllocationSite>::null()),
231        JSArray);
232    RETURN_ON_EXCEPTION(isolate,
233                        JSObject::SetOwnPropertyIgnoreAttributes(
234                            site, isolate->factory()->call_site_info_symbol(),
235                            frame, DONT_ENUM),
236                        JSArray);
237    sites->set(i, *site);
238  }
239
240  return isolate->factory()->NewJSArrayWithElements(sites);
241}
242
243MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
244                                      IncrementalStringBuilder* builder) {
245  MaybeHandle<String> err_str =
246      ErrorUtils::ToString(isolate, Handle<Object>::cast(error));
247  if (err_str.is_null()) {
248    // Error.toString threw. Try to return a string representation of the thrown
249    // exception instead.
250
251    DCHECK(isolate->has_pending_exception());
252    Handle<Object> pending_exception =
253        handle(isolate->pending_exception(), isolate);
254    isolate->clear_pending_exception();
255    isolate->set_external_caught_exception(false);
256
257    err_str = ErrorUtils::ToString(isolate, pending_exception);
258    if (err_str.is_null()) {
259      // Formatting the thrown exception threw again, give up.
260      DCHECK(isolate->has_pending_exception());
261      isolate->clear_pending_exception();
262      isolate->set_external_caught_exception(false);
263      builder->AppendCStringLiteral("<error>");
264    } else {
265      // Formatted thrown exception successfully, append it.
266      builder->AppendCStringLiteral("<error: ");
267      builder->AppendString(err_str.ToHandleChecked());
268      builder->AppendCharacter('>');
269    }
270  } else {
271    builder->AppendString(err_str.ToHandleChecked());
272  }
273
274  return error;
275}
276
277class V8_NODISCARD PrepareStackTraceScope {
278 public:
279  explicit PrepareStackTraceScope(Isolate* isolate) : isolate_(isolate) {
280    DCHECK(!isolate_->formatting_stack_trace());
281    isolate_->set_formatting_stack_trace(true);
282  }
283
284  ~PrepareStackTraceScope() { isolate_->set_formatting_stack_trace(false); }
285
286  PrepareStackTraceScope(const PrepareStackTraceScope&) = delete;
287  PrepareStackTraceScope& operator=(const PrepareStackTraceScope&) = delete;
288
289 private:
290  Isolate* isolate_;
291};
292
293}  // namespace
294
295// static
296MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
297                                                 Handle<JSObject> error,
298                                                 Handle<Object> raw_stack) {
299  if (FLAG_correctness_fuzzer_suppressions) {
300    return isolate->factory()->empty_string();
301  }
302  DCHECK(raw_stack->IsFixedArray());
303  Handle<FixedArray> elems = Handle<FixedArray>::cast(raw_stack);
304
305  const bool in_recursion = isolate->formatting_stack_trace();
306  const bool has_overflowed = i::StackLimitCheck{isolate}.HasOverflowed();
307  Handle<Context> error_context;
308  if (!in_recursion && !has_overflowed &&
309      error->GetCreationContext().ToHandle(&error_context)) {
310    DCHECK(error_context->IsNativeContext());
311
312    if (isolate->HasPrepareStackTraceCallback()) {
313      PrepareStackTraceScope scope(isolate);
314
315      Handle<JSArray> sites;
316      ASSIGN_RETURN_ON_EXCEPTION(isolate, sites, GetStackFrames(isolate, elems),
317                                 Object);
318
319      Handle<Object> result;
320      ASSIGN_RETURN_ON_EXCEPTION(
321          isolate, result,
322          isolate->RunPrepareStackTraceCallback(error_context, error, sites),
323          Object);
324      return result;
325    } else {
326      Handle<JSFunction> global_error =
327          handle(error_context->error_function(), isolate);
328
329      // If there's a user-specified "prepareStackTrace" function, call it on
330      // the frames and use its result.
331
332      Handle<Object> prepare_stack_trace;
333      ASSIGN_RETURN_ON_EXCEPTION(
334          isolate, prepare_stack_trace,
335          JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"),
336          Object);
337
338      if (prepare_stack_trace->IsJSFunction()) {
339        PrepareStackTraceScope scope(isolate);
340
341        isolate->CountUsage(v8::Isolate::kErrorPrepareStackTrace);
342
343        Handle<JSArray> sites;
344        ASSIGN_RETURN_ON_EXCEPTION(isolate, sites,
345                                   GetStackFrames(isolate, elems), Object);
346
347        const int argc = 2;
348        base::ScopedVector<Handle<Object>> argv(argc);
349        argv[0] = error;
350        argv[1] = sites;
351
352        Handle<Object> result;
353
354        ASSIGN_RETURN_ON_EXCEPTION(
355            isolate, result,
356            Execution::Call(isolate, prepare_stack_trace, global_error, argc,
357                            argv.begin()),
358            Object);
359
360        return result;
361      }
362    }
363  }
364
365  // Otherwise, run our internal formatting logic.
366  IncrementalStringBuilder builder(isolate);
367
368  RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder),
369                      Object);
370
371  for (int i = 0; i < elems->length(); ++i) {
372    builder.AppendCStringLiteral("\n    at ");
373
374    Handle<CallSiteInfo> frame(CallSiteInfo::cast(elems->get(i)), isolate);
375    SerializeCallSiteInfo(isolate, frame, &builder);
376
377    if (isolate->has_pending_exception()) {
378      // CallSite.toString threw. Parts of the current frame might have been
379      // stringified already regardless. Still, try to append a string
380      // representation of the thrown exception.
381
382      Handle<Object> pending_exception =
383          handle(isolate->pending_exception(), isolate);
384      isolate->clear_pending_exception();
385      isolate->set_external_caught_exception(false);
386
387      MaybeHandle<String> exception_string =
388          ErrorUtils::ToString(isolate, pending_exception);
389      if (exception_string.is_null()) {
390        // Formatting the thrown exception threw again, give up.
391
392        builder.AppendCStringLiteral("<error>");
393      } else {
394        // Formatted thrown exception successfully, append it.
395        builder.AppendCStringLiteral("<error: ");
396        builder.AppendString(exception_string.ToHandleChecked());
397        builder.AppendCStringLiteral("<error>");
398      }
399    }
400  }
401
402  return builder.Finish();
403}
404
405Handle<String> MessageFormatter::Format(Isolate* isolate, MessageTemplate index,
406                                        Handle<Object> arg0,
407                                        Handle<Object> arg1,
408                                        Handle<Object> arg2) {
409  Factory* factory = isolate->factory();
410  Handle<String> arg0_string = factory->empty_string();
411  if (!arg0.is_null()) {
412    arg0_string = Object::NoSideEffectsToString(isolate, arg0);
413  }
414  Handle<String> arg1_string = factory->empty_string();
415  if (!arg1.is_null()) {
416    arg1_string = Object::NoSideEffectsToString(isolate, arg1);
417  }
418  Handle<String> arg2_string = factory->empty_string();
419  if (!arg2.is_null()) {
420    arg2_string = Object::NoSideEffectsToString(isolate, arg2);
421  }
422  MaybeHandle<String> maybe_result_string = MessageFormatter::Format(
423      isolate, index, arg0_string, arg1_string, arg2_string);
424  Handle<String> result_string;
425  if (!maybe_result_string.ToHandle(&result_string)) {
426    DCHECK(isolate->has_pending_exception());
427    isolate->clear_pending_exception();
428    return factory->InternalizeString(base::StaticCharVector("<error>"));
429  }
430  // A string that has been obtained from JS code in this way is
431  // likely to be a complicated ConsString of some sort.  We flatten it
432  // here to improve the efficiency of converting it to a C string and
433  // other operations that are likely to take place (see GetLocalizedMessage
434  // for example).
435  return String::Flatten(isolate, result_string);
436}
437
438const char* MessageFormatter::TemplateString(MessageTemplate index) {
439  switch (index) {
440#define CASE(NAME, STRING)       \
441  case MessageTemplate::k##NAME: \
442    return STRING;
443    MESSAGE_TEMPLATES(CASE)
444#undef CASE
445    case MessageTemplate::kMessageCount:
446    default:
447      return nullptr;
448  }
449}
450
451MaybeHandle<String> MessageFormatter::Format(Isolate* isolate,
452                                             MessageTemplate index,
453                                             Handle<String> arg0,
454                                             Handle<String> arg1,
455                                             Handle<String> arg2) {
456  const char* template_string = TemplateString(index);
457  if (template_string == nullptr) {
458    isolate->ThrowIllegalOperation();
459    return MaybeHandle<String>();
460  }
461
462  IncrementalStringBuilder builder(isolate);
463
464  unsigned int i = 0;
465  Handle<String> args[] = {arg0, arg1, arg2};
466  for (const char* c = template_string; *c != '\0'; c++) {
467    if (*c == '%') {
468      // %% results in verbatim %.
469      if (*(c + 1) == '%') {
470        c++;
471        builder.AppendCharacter('%');
472      } else {
473        DCHECK(i < arraysize(args));
474        Handle<String> arg = args[i++];
475        builder.AppendString(arg);
476      }
477    } else {
478      builder.AppendCharacter(*c);
479    }
480  }
481
482  return builder.Finish();
483}
484
485MaybeHandle<JSObject> ErrorUtils::Construct(Isolate* isolate,
486                                            Handle<JSFunction> target,
487                                            Handle<Object> new_target,
488                                            Handle<Object> message,
489                                            Handle<Object> options) {
490  FrameSkipMode mode = SKIP_FIRST;
491  Handle<Object> caller;
492
493  // When we're passed a JSFunction as new target, we can skip frames until that
494  // specific function is seen instead of unconditionally skipping the first
495  // frame.
496  if (new_target->IsJSFunction()) {
497    mode = SKIP_UNTIL_SEEN;
498    caller = new_target;
499  }
500
501  return ErrorUtils::Construct(isolate, target, new_target, message, options,
502                               mode, caller,
503                               ErrorUtils::StackTraceCollection::kEnabled);
504}
505
506MaybeHandle<JSObject> ErrorUtils::Construct(
507    Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
508    Handle<Object> message, Handle<Object> options, FrameSkipMode mode,
509    Handle<Object> caller, StackTraceCollection stack_trace_collection) {
510  if (FLAG_correctness_fuzzer_suppressions) {
511    // Abort range errors in correctness fuzzing, as their causes differ
512    // accross correctness-fuzzing scenarios.
513    if (target.is_identical_to(isolate->range_error_function())) {
514      FATAL("Aborting on range error");
515    }
516    // Ignore error messages in correctness fuzzing, because the spec leaves
517    // room for undefined behavior.
518    message = isolate->factory()->InternalizeUtf8String(
519        "Message suppressed for fuzzers (--correctness-fuzzer-suppressions)");
520  }
521
522  // 1. If NewTarget is undefined, let newTarget be the active function object,
523  // else let newTarget be NewTarget.
524  Handle<JSReceiver> new_target_recv =
525      new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
526                                 : Handle<JSReceiver>::cast(target);
527
528  // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
529  //    « [[ErrorData]] »).
530  Handle<JSObject> err;
531  ASSIGN_RETURN_ON_EXCEPTION(
532      isolate, err,
533      JSObject::New(target, new_target_recv, Handle<AllocationSite>::null()),
534      JSObject);
535
536  // 3. If message is not undefined, then
537  //  a. Let msg be ? ToString(message).
538  //  b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
539  //     true, [[Enumerable]]: false, [[Configurable]]: true}.
540  //  c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
541  // 4. Return O.
542  if (!message->IsUndefined(isolate)) {
543    Handle<String> msg_string;
544    ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
545                               Object::ToString(isolate, message), JSObject);
546    RETURN_ON_EXCEPTION(
547        isolate,
548        JSObject::SetOwnPropertyIgnoreAttributes(
549            err, isolate->factory()->message_string(), msg_string, DONT_ENUM),
550        JSObject);
551  }
552
553  if (FLAG_harmony_error_cause && !options->IsUndefined(isolate)) {
554    // If Type(options) is Object and ? HasProperty(options, "cause") then
555    //   a. Let cause be ? Get(options, "cause").
556    //   b. Perform ! CreateNonEnumerableDataPropertyOrThrow(O, "cause", cause).
557    Handle<Name> cause_string = isolate->factory()->cause_string();
558    if (options->IsJSReceiver()) {
559      Handle<JSReceiver> js_options = Handle<JSReceiver>::cast(options);
560      Maybe<bool> has_cause =
561          JSObject::HasProperty(isolate, js_options, cause_string);
562      if (has_cause.IsNothing()) {
563        DCHECK((isolate)->has_pending_exception());
564        return MaybeHandle<JSObject>();
565      }
566      if (has_cause.ToChecked()) {
567        Handle<Object> cause;
568        ASSIGN_RETURN_ON_EXCEPTION(
569            isolate, cause,
570            JSObject::GetProperty(isolate, js_options, cause_string), JSObject);
571        RETURN_ON_EXCEPTION(isolate,
572                            JSObject::SetOwnPropertyIgnoreAttributes(
573                                err, cause_string, cause, DONT_ENUM),
574                            JSObject);
575      }
576    }
577  }
578
579  switch (stack_trace_collection) {
580    case StackTraceCollection::kEnabled:
581      RETURN_ON_EXCEPTION(isolate,
582                          isolate->CaptureAndSetErrorStack(err, mode, caller),
583                          JSObject);
584      break;
585    case StackTraceCollection::kDisabled:
586      break;
587  }
588  return err;
589}
590
591namespace {
592
593MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
594                                               Handle<JSReceiver> recv,
595                                               Handle<String> key,
596                                               Handle<String> default_str) {
597  Handle<Object> obj;
598  ASSIGN_RETURN_ON_EXCEPTION(isolate, obj,
599                             JSObject::GetProperty(isolate, recv, key), String);
600
601  Handle<String> str;
602  if (obj->IsUndefined(isolate)) {
603    str = default_str;
604  } else {
605    ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
606                               String);
607  }
608
609  return str;
610}
611
612}  // namespace
613
614// ES6 section 19.5.3.4 Error.prototype.toString ( )
615MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
616                                         Handle<Object> receiver) {
617  // 1. Let O be the this value.
618  // 2. If Type(O) is not Object, throw a TypeError exception.
619  if (!receiver->IsJSReceiver()) {
620    return isolate->Throw<String>(isolate->factory()->NewTypeError(
621        MessageTemplate::kIncompatibleMethodReceiver,
622        isolate->factory()->NewStringFromAsciiChecked(
623            "Error.prototype.toString"),
624        receiver));
625  }
626  Handle<JSReceiver> recv = Handle<JSReceiver>::cast(receiver);
627
628  // 3. Let name be ? Get(O, "name").
629  // 4. If name is undefined, let name be "Error"; otherwise let name be
630  // ? ToString(name).
631  Handle<String> name_key = isolate->factory()->name_string();
632  Handle<String> name_default = isolate->factory()->Error_string();
633  Handle<String> name;
634  ASSIGN_RETURN_ON_EXCEPTION(
635      isolate, name,
636      GetStringPropertyOrDefault(isolate, recv, name_key, name_default),
637      String);
638
639  // 5. Let msg be ? Get(O, "message").
640  // 6. If msg is undefined, let msg be the empty String; otherwise let msg be
641  // ? ToString(msg).
642  Handle<String> msg_key = isolate->factory()->message_string();
643  Handle<String> msg_default = isolate->factory()->empty_string();
644  Handle<String> msg;
645  ASSIGN_RETURN_ON_EXCEPTION(
646      isolate, msg,
647      GetStringPropertyOrDefault(isolate, recv, msg_key, msg_default), String);
648
649  // 7. If name is the empty String, return msg.
650  // 8. If msg is the empty String, return name.
651  if (name->length() == 0) return msg;
652  if (msg->length() == 0) return name;
653
654  // 9. Return the result of concatenating name, the code unit 0x003A (COLON),
655  // the code unit 0x0020 (SPACE), and msg.
656  IncrementalStringBuilder builder(isolate);
657  builder.AppendString(name);
658  builder.AppendCStringLiteral(": ");
659  builder.AppendString(msg);
660
661  Handle<String> result;
662  ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
663  return result;
664}
665
666namespace {
667
668Handle<String> DoFormatMessage(Isolate* isolate, MessageTemplate index,
669                               Handle<Object> arg0, Handle<Object> arg1,
670                               Handle<Object> arg2) {
671  Handle<String> arg0_str = Object::NoSideEffectsToString(isolate, arg0);
672  Handle<String> arg1_str = Object::NoSideEffectsToString(isolate, arg1);
673  Handle<String> arg2_str = Object::NoSideEffectsToString(isolate, arg2);
674
675  isolate->native_context()->IncrementErrorsThrown();
676
677  Handle<String> msg;
678  if (!MessageFormatter::Format(isolate, index, arg0_str, arg1_str, arg2_str)
679           .ToHandle(&msg)) {
680    DCHECK(isolate->has_pending_exception());
681    isolate->clear_pending_exception();
682    isolate->set_external_caught_exception(false);
683    return isolate->factory()->NewStringFromAsciiChecked("<error>");
684  }
685
686  return msg;
687}
688
689}  // namespace
690
691// static
692Handle<JSObject> ErrorUtils::MakeGenericError(
693    Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
694    Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
695    FrameSkipMode mode) {
696  if (FLAG_clear_exceptions_on_js_entry) {
697    // This function used to be implemented in JavaScript, and JSEntry
698    // clears any pending exceptions - so whenever we'd call this from C++,
699    // pending exceptions would be cleared. Preserve this behavior.
700    isolate->clear_pending_exception();
701  }
702  Handle<String> msg = DoFormatMessage(isolate, index, arg0, arg1, arg2);
703  Handle<Object> options = isolate->factory()->undefined_value();
704
705  DCHECK(mode != SKIP_UNTIL_SEEN);
706
707  Handle<Object> no_caller;
708  // The call below can't fail because constructor is a builtin.
709  DCHECK(constructor->shared().HasBuiltinId());
710  return ErrorUtils::Construct(isolate, constructor, constructor, msg, options,
711                               mode, no_caller, StackTraceCollection::kEnabled)
712      .ToHandleChecked();
713}
714
715namespace {
716
717bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
718  JavaScriptFrameIterator it(isolate);
719  if (!it.done()) {
720    // Compute the location from the function and the relocation info of the
721    // baseline code. For optimized code this will use the deoptimization
722    // information to get canonical location information.
723    std::vector<FrameSummary> frames;
724    it.frame()->Summarize(&frames);
725    auto& summary = frames.back().AsJavaScript();
726    Handle<SharedFunctionInfo> shared(summary.function()->shared(), isolate);
727    Handle<Object> script(shared->script(), isolate);
728    SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
729    int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
730    if (script->IsScript() &&
731        !(Handle<Script>::cast(script)->source().IsUndefined(isolate))) {
732      Handle<Script> casted_script = Handle<Script>::cast(script);
733      *target = MessageLocation(casted_script, pos, pos + 1, shared);
734      return true;
735    }
736  }
737  return false;
738}
739
740Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
741  IncrementalStringBuilder builder(isolate);
742
743  builder.AppendString(Object::TypeOf(isolate, object));
744  if (object->IsString()) {
745    builder.AppendCStringLiteral(" \"");
746    Handle<String> string = Handle<String>::cast(object);
747    // This threshold must be sufficiently far below String::kMaxLength that
748    // the {builder}'s result can never exceed that limit.
749    constexpr int kMaxPrintedStringLength = 100;
750    if (string->length() <= kMaxPrintedStringLength) {
751      builder.AppendString(string);
752    } else {
753      string = isolate->factory()->NewProperSubString(string, 0,
754                                                      kMaxPrintedStringLength);
755      builder.AppendString(string);
756      builder.AppendCStringLiteral("<...>");
757    }
758    builder.AppendCStringLiteral("\"");
759  } else if (object->IsNull(isolate)) {
760    builder.AppendCStringLiteral(" null");
761  } else if (object->IsTrue(isolate)) {
762    builder.AppendCStringLiteral(" true");
763  } else if (object->IsFalse(isolate)) {
764    builder.AppendCStringLiteral(" false");
765  } else if (object->IsNumber()) {
766    builder.AppendCharacter(' ');
767    builder.AppendString(isolate->factory()->NumberToString(object));
768  }
769
770  return builder.Finish().ToHandleChecked();
771}
772
773Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object,
774                              MessageLocation* location,
775                              CallPrinter::ErrorHint* hint) {
776  if (ComputeLocation(isolate, location)) {
777    UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
778        isolate, *location->shared());
779    UnoptimizedCompileState compile_state;
780    ReusableUnoptimizedCompileState reusable_state(isolate);
781    ParseInfo info(isolate, flags, &compile_state, &reusable_state);
782    if (parsing::ParseAny(&info, location->shared(), isolate,
783                          parsing::ReportStatisticsMode::kNo)) {
784      info.ast_value_factory()->Internalize(isolate);
785      CallPrinter printer(isolate, location->shared()->IsUserJavaScript());
786      Handle<String> str = printer.Print(info.literal(), location->start_pos());
787      *hint = printer.GetErrorHint();
788      if (str->length() > 0) return str;
789    }
790  }
791  return BuildDefaultCallSite(isolate, object);
792}
793
794MessageTemplate UpdateErrorTemplate(CallPrinter::ErrorHint hint,
795                                    MessageTemplate default_id) {
796  switch (hint) {
797    case CallPrinter::ErrorHint::kNormalIterator:
798      return MessageTemplate::kNotIterable;
799
800    case CallPrinter::ErrorHint::kCallAndNormalIterator:
801      return MessageTemplate::kNotCallableOrIterable;
802
803    case CallPrinter::ErrorHint::kAsyncIterator:
804      return MessageTemplate::kNotAsyncIterable;
805
806    case CallPrinter::ErrorHint::kCallAndAsyncIterator:
807      return MessageTemplate::kNotCallableOrAsyncIterable;
808
809    case CallPrinter::ErrorHint::kNone:
810      return default_id;
811  }
812}
813
814}  // namespace
815
816Handle<JSObject> ErrorUtils::NewIteratorError(Isolate* isolate,
817                                              Handle<Object> source) {
818  MessageLocation location;
819  CallPrinter::ErrorHint hint = CallPrinter::ErrorHint::kNone;
820  Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
821  MessageTemplate id = MessageTemplate::kNotIterableNoSymbolLoad;
822
823  if (hint == CallPrinter::ErrorHint::kNone) {
824    Handle<Symbol> iterator_symbol = isolate->factory()->iterator_symbol();
825    return isolate->factory()->NewTypeError(id, callsite, iterator_symbol);
826  }
827
828  id = UpdateErrorTemplate(hint, id);
829  return isolate->factory()->NewTypeError(id, callsite);
830}
831
832Object ErrorUtils::ThrowSpreadArgError(Isolate* isolate, MessageTemplate id,
833                                       Handle<Object> object) {
834  MessageLocation location;
835  Handle<String> callsite;
836  if (ComputeLocation(isolate, &location)) {
837    UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
838        isolate, *location.shared());
839    UnoptimizedCompileState compile_state;
840    ReusableUnoptimizedCompileState reusable_state(isolate);
841    ParseInfo info(isolate, flags, &compile_state, &reusable_state);
842    if (parsing::ParseAny(&info, location.shared(), isolate,
843                          parsing::ReportStatisticsMode::kNo)) {
844      info.ast_value_factory()->Internalize(isolate);
845      CallPrinter printer(isolate, location.shared()->IsUserJavaScript(),
846                          CallPrinter::SpreadErrorInArgsHint::kErrorInArgs);
847      Handle<String> str = printer.Print(info.literal(), location.start_pos());
848      callsite =
849          str->length() > 0 ? str : BuildDefaultCallSite(isolate, object);
850
851      if (printer.spread_arg() != nullptr) {
852        // Change the message location to point at the property name.
853        int pos = printer.spread_arg()->position();
854        location =
855            MessageLocation(location.script(), pos, pos + 1, location.shared());
856      }
857    } else {
858      callsite = BuildDefaultCallSite(isolate, object);
859    }
860  }
861
862  isolate->ThrowAt(isolate->factory()->NewTypeError(id, callsite, object),
863                   &location);
864  return ReadOnlyRoots(isolate).exception();
865}
866
867Handle<JSObject> ErrorUtils::NewCalledNonCallableError(Isolate* isolate,
868                                                       Handle<Object> source) {
869  MessageLocation location;
870  CallPrinter::ErrorHint hint = CallPrinter::ErrorHint::kNone;
871  Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
872  MessageTemplate id = MessageTemplate::kCalledNonCallable;
873  id = UpdateErrorTemplate(hint, id);
874  return isolate->factory()->NewTypeError(id, callsite);
875}
876
877Handle<JSObject> ErrorUtils::NewConstructedNonConstructable(
878    Isolate* isolate, Handle<Object> source) {
879  MessageLocation location;
880  CallPrinter::ErrorHint hint = CallPrinter::ErrorHint::kNone;
881  Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
882  MessageTemplate id = MessageTemplate::kNotConstructor;
883  return isolate->factory()->NewTypeError(id, callsite);
884}
885
886Object ErrorUtils::ThrowLoadFromNullOrUndefined(Isolate* isolate,
887                                                Handle<Object> object,
888                                                MaybeHandle<Object> key) {
889  DCHECK(object->IsNullOrUndefined());
890
891  MaybeHandle<String> maybe_property_name;
892
893  // Try to extract the property name from the given key, if any.
894  Handle<Object> key_handle;
895  if (key.ToHandle(&key_handle)) {
896    if (key_handle->IsString()) {
897      maybe_property_name = Handle<String>::cast(key_handle);
898    } else {
899      maybe_property_name =
900          Object::NoSideEffectsToMaybeString(isolate, key_handle);
901    }
902  }
903
904  Handle<String> callsite;
905
906  // Inline the RenderCallSite logic here so that we can additonally access the
907  // destructuring property.
908  bool location_computed = false;
909  bool is_destructuring = false;
910  MessageLocation location;
911  if (ComputeLocation(isolate, &location)) {
912    location_computed = true;
913
914    UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
915        isolate, *location.shared());
916    UnoptimizedCompileState compile_state;
917    ReusableUnoptimizedCompileState reusable_state(isolate);
918    ParseInfo info(isolate, flags, &compile_state, &reusable_state);
919    if (parsing::ParseAny(&info, location.shared(), isolate,
920                          parsing::ReportStatisticsMode::kNo)) {
921      info.ast_value_factory()->Internalize(isolate);
922      CallPrinter printer(isolate, location.shared()->IsUserJavaScript());
923      Handle<String> str = printer.Print(info.literal(), location.start_pos());
924
925      int pos = -1;
926      is_destructuring = printer.destructuring_assignment() != nullptr;
927
928      if (is_destructuring) {
929        // If we don't have one yet, try to extract the property name from the
930        // destructuring property in the AST.
931        ObjectLiteralProperty* destructuring_prop =
932            printer.destructuring_prop();
933        if (maybe_property_name.is_null() && destructuring_prop != nullptr &&
934            destructuring_prop->key()->IsPropertyName()) {
935          maybe_property_name = destructuring_prop->key()
936                                    ->AsLiteral()
937                                    ->AsRawPropertyName()
938                                    ->string();
939          // Change the message location to point at the property name.
940          pos = destructuring_prop->key()->position();
941        }
942        if (maybe_property_name.is_null()) {
943          // Change the message location to point at the destructured value.
944          pos = printer.destructuring_assignment()->value()->position();
945        }
946
947        // If we updated the pos to a valid pos, rewrite the location.
948        if (pos != -1) {
949          location = MessageLocation(location.script(), pos, pos + 1,
950                                     location.shared());
951        }
952      }
953
954      if (str->length() > 0) callsite = str;
955    }
956  }
957
958  if (callsite.is_null()) {
959    callsite = BuildDefaultCallSite(isolate, object);
960  }
961
962  Handle<JSObject> error;
963  Handle<String> property_name;
964  if (is_destructuring) {
965    if (maybe_property_name.ToHandle(&property_name)) {
966      error = isolate->factory()->NewTypeError(
967          MessageTemplate::kNonCoercibleWithProperty, property_name, callsite,
968          object);
969    } else {
970      error = isolate->factory()->NewTypeError(MessageTemplate::kNonCoercible,
971                                               callsite, object);
972    }
973  } else {
974    if (!key.ToHandle(&key_handle) ||
975        !maybe_property_name.ToHandle(&property_name)) {
976      error = isolate->factory()->NewTypeError(
977          MessageTemplate::kNonObjectPropertyLoad, object);
978    } else if (*key_handle == ReadOnlyRoots(isolate).iterator_symbol()) {
979      error = NewIteratorError(isolate, object);
980    } else {
981      error = isolate->factory()->NewTypeError(
982          MessageTemplate::kNonObjectPropertyLoadWithProperty, object,
983          property_name);
984    }
985  }
986
987  if (location_computed) {
988    isolate->ThrowAt(error, &location);
989  } else {
990    isolate->Throw(*error);
991  }
992  return ReadOnlyRoots(isolate).exception();
993}
994
995// static
996MaybeHandle<Object> ErrorUtils::GetFormattedStack(
997    Isolate* isolate, Handle<JSObject> error_object) {
998  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.stack_trace"), __func__);
999
1000  Handle<Object> error_stack = JSReceiver::GetDataProperty(
1001      isolate, error_object, isolate->factory()->error_stack_symbol());
1002  if (error_stack->IsErrorStackData()) {
1003    Handle<ErrorStackData> error_stack_data =
1004        Handle<ErrorStackData>::cast(error_stack);
1005    if (error_stack_data->HasFormattedStack()) {
1006      return handle(error_stack_data->formatted_stack(), isolate);
1007    }
1008    ErrorStackData::EnsureStackFrameInfos(isolate, error_stack_data);
1009    Handle<Object> formatted_stack;
1010    ASSIGN_RETURN_ON_EXCEPTION(
1011        isolate, formatted_stack,
1012        FormatStackTrace(isolate, error_object,
1013                         handle(error_stack_data->call_site_infos(), isolate)),
1014        Object);
1015    error_stack_data->set_formatted_stack(*formatted_stack);
1016    return formatted_stack;
1017  }
1018
1019  if (error_stack->IsFixedArray()) {
1020    Handle<Object> formatted_stack;
1021    ASSIGN_RETURN_ON_EXCEPTION(
1022        isolate, formatted_stack,
1023        FormatStackTrace(isolate, error_object,
1024                         Handle<FixedArray>::cast(error_stack)),
1025        Object);
1026    RETURN_ON_EXCEPTION(
1027        isolate,
1028        JSObject::SetProperty(isolate, error_object,
1029                              isolate->factory()->error_stack_symbol(),
1030                              formatted_stack, StoreOrigin::kMaybeKeyed,
1031                              Just(ShouldThrow::kThrowOnError)),
1032        Object);
1033    return formatted_stack;
1034  }
1035
1036  return error_stack;
1037}
1038
1039// static
1040void ErrorUtils::SetFormattedStack(Isolate* isolate,
1041                                   Handle<JSObject> error_object,
1042                                   Handle<Object> formatted_stack) {
1043  Handle<Object> error_stack = JSReceiver::GetDataProperty(
1044      isolate, error_object, isolate->factory()->error_stack_symbol());
1045  if (error_stack->IsErrorStackData()) {
1046    Handle<ErrorStackData> error_stack_data =
1047        Handle<ErrorStackData>::cast(error_stack);
1048    ErrorStackData::EnsureStackFrameInfos(isolate, error_stack_data);
1049    error_stack_data->set_formatted_stack(*formatted_stack);
1050  } else {
1051    JSObject::SetProperty(isolate, error_object,
1052                          isolate->factory()->error_stack_symbol(),
1053                          formatted_stack, StoreOrigin::kMaybeKeyed,
1054                          Just(ShouldThrow::kThrowOnError))
1055        .Check();
1056  }
1057}
1058
1059}  // namespace internal
1060}  // namespace v8
1061