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