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