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