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