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