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 396737 : MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
26 : int end_pos)
27 793474 : : script_(script), start_pos_(start_pos), end_pos_(end_pos) {}
28 976101 : 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 976101 : shared_(shared) {}
34 8182617 : 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 1341 : void MessageHandler::DefaultMessageReport(Isolate* isolate,
39 1341 : const MessageLocation* loc,
40 : Handle<Object> message_obj) {
41 1341 : std::unique_ptr<char[]> str = GetLocalizedMessage(isolate, message_obj);
42 1341 : 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 2682 : if (data->IsString())
49 0 : data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
50 : PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
51 1341 : loc->start_pos(), str.get());
52 : }
53 1341 : }
54 :
55 1360616 : Handle<JSMessageObject> MessageHandler::MakeMessageObject(
56 1356774 : 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 1360616 : Handle<Script> script_handle = isolate->factory()->empty_script();
63 1360616 : if (location != nullptr) {
64 : start = location->start_pos();
65 : end = location->end_pos();
66 1356774 : script_handle = location->script();
67 : }
68 :
69 : Handle<Object> stack_frames_handle = stack_frames.is_null()
70 : ? Handle<Object>::cast(factory->undefined_value())
71 2720749 : : Handle<Object>::cast(stack_frames);
72 :
73 : Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
74 1360616 : message, argument, start, end, script_handle, stack_frames_handle);
75 :
76 1360616 : return message_obj;
77 : }
78 :
79 8612 : 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 8612 : 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 7976 : if (isolate->has_pending_exception()) {
91 : exception_object = isolate->pending_exception();
92 : }
93 : Handle<Object> exception(exception_object, isolate);
94 :
95 7976 : Isolate::ExceptionScope exception_scope(isolate);
96 7976 : 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 15952 : 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 8066 : if (argument->IsJSError()) {
108 3944 : maybe_stringified = Object::NoSideEffectsToString(isolate, argument);
109 : } else {
110 89 : v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
111 89 : catcher.SetVerbose(false);
112 89 : catcher.SetCaptureMessage(false);
113 :
114 89 : maybe_stringified = Object::ToString(isolate, argument);
115 : }
116 :
117 4033 : if (!maybe_stringified.ToHandle(&stringified)) {
118 : DCHECK(isolate->has_pending_exception());
119 10 : isolate->clear_pending_exception();
120 : isolate->set_external_caught_exception(false);
121 : stringified =
122 10 : isolate->factory()->NewStringFromAsciiChecked("exception");
123 : }
124 4033 : message->set_argument(*stringified);
125 : }
126 :
127 7976 : v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception);
128 7976 : ReportMessageNoExceptions(isolate, loc, message, api_exception_obj);
129 : } else {
130 636 : ReportMessageNoExceptions(isolate, loc, message, v8::Local<v8::Value>());
131 : }
132 8612 : }
133 :
134 8612 : 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 8612 : int error_level = api_message_obj->ErrorLevel();
139 :
140 : Handle<TemplateList> global_listeners =
141 : isolate->factory()->message_listeners();
142 8612 : int global_length = global_listeners->length();
143 8612 : if (global_length == 0) {
144 1341 : DefaultMessageReport(isolate, loc, message);
145 1341 : if (isolate->has_scheduled_exception()) {
146 0 : isolate->clear_scheduled_exception();
147 : }
148 : } else {
149 7415 : for (int i = 0; i < global_length; i++) {
150 : HandleScope scope(isolate);
151 14830 : if (global_listeners->get(i)->IsUndefined(isolate)) continue;
152 14474 : FixedArray listener = FixedArray::cast(global_listeners->get(i));
153 : Foreign callback_obj = Foreign::cast(listener->get(0));
154 : int32_t message_levels =
155 7237 : static_cast<int32_t>(Smi::ToInt(listener->get(2)));
156 7237 : 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 7237 : isolate, RuntimeCallCounterId::kMessageListenerCallback);
165 : // Do not allow exceptions to propagate.
166 14474 : v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
167 14474 : callback(api_message_obj, callback_data->IsUndefined(isolate)
168 : ? api_exception_obj
169 7237 : : v8::Utils::ToLocal(callback_data));
170 : }
171 7237 : if (isolate->has_scheduled_exception()) {
172 0 : isolate->clear_scheduled_exception();
173 : }
174 : }
175 : }
176 8612 : }
177 :
178 :
179 4201 : Handle<String> MessageHandler::GetMessage(Isolate* isolate,
180 : Handle<Object> data) {
181 4201 : Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
182 : Handle<Object> arg = Handle<Object>(message->argument(), isolate);
183 4201 : return MessageFormatter::FormatMessage(isolate, message->type(), arg);
184 : }
185 :
186 1341 : std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
187 : Isolate* isolate, Handle<Object> data) {
188 : HandleScope scope(isolate);
189 4023 : return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
190 : }
191 :
192 : namespace {
193 :
194 970 : Object EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
195 970 : if (!script->has_eval_from_shared()) {
196 9 : return ReadOnlyRoots(isolate).undefined_value();
197 : }
198 :
199 1922 : Handle<SharedFunctionInfo> shared(script->eval_from_shared(), isolate);
200 : // Find the name of the function calling eval.
201 961 : if (shared->Name()->BooleanValue(isolate)) {
202 767 : return shared->Name();
203 : }
204 :
205 194 : return shared->inferred_name();
206 : }
207 :
208 970 : Object EvalFromScript(Isolate* isolate, Handle<Script> script) {
209 970 : 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 1922 : isolate);
215 1922 : return eval_from_shared->script()->IsScript()
216 1922 : ? eval_from_shared->script()
217 1922 : : ReadOnlyRoots(isolate).undefined_value();
218 : }
219 :
220 979 : MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
221 1958 : Handle<Object> sourceURL(script->GetNameOrSourceURL(), isolate);
222 1958 : if (!sourceURL->IsUndefined(isolate)) {
223 : DCHECK(sourceURL->IsString());
224 9 : return Handle<String>::cast(sourceURL);
225 : }
226 :
227 970 : IncrementalStringBuilder builder(isolate);
228 : builder.AppendCString("eval at ");
229 :
230 : Handle<Object> eval_from_function_name =
231 970 : handle(EvalFromFunctionName(isolate, script), isolate);
232 970 : 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 970 : handle(EvalFromScript(isolate, script), isolate);
244 1940 : if (eval_from_script_obj->IsScript()) {
245 : Handle<Script> eval_from_script =
246 961 : Handle<Script>::cast(eval_from_script_obj);
247 : builder.AppendCString(" (");
248 961 : 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 889 : Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
259 1778 : if (eval_from_script->name()->IsString()) {
260 889 : builder.AppendString(Handle<String>::cast(name_obj));
261 :
262 : Script::PositionInfo info;
263 1778 : if (Script::GetPositionInfo(eval_from_script, script->GetEvalPosition(),
264 1778 : &info, Script::NO_OFFSET)) {
265 : builder.AppendCString(":");
266 :
267 : Handle<String> str = isolate->factory()->NumberToString(
268 1778 : handle(Smi::FromInt(info.line + 1), isolate));
269 889 : builder.AppendString(str);
270 :
271 : builder.AppendCString(":");
272 :
273 : str = isolate->factory()->NumberToString(
274 1778 : handle(Smi::FromInt(info.column + 1), isolate));
275 889 : 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 1940 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
287 970 : return result;
288 : }
289 :
290 : } // namespace
291 :
292 916 : Handle<Object> StackFrameBase::GetEvalOrigin() {
293 925 : if (!HasScript()) return isolate_->factory()->undefined_value();
294 1814 : return FormatEvalOrigin(isolate_, GetScript()).ToHandleChecked();
295 : }
296 :
297 10738 : int StackFrameBase::GetScriptId() const {
298 10738 : if (!HasScript()) return kNone;
299 21476 : return GetScript()->id();
300 : }
301 :
302 74700 : bool StackFrameBase::IsEval() {
303 147882 : return HasScript() &&
304 221064 : GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL;
305 : }
306 :
307 455082 : void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
308 : int frame_ix) {
309 : DCHECK(!array->IsWasmFrame(frame_ix));
310 455082 : isolate_ = isolate;
311 910164 : receiver_ = handle(array->Receiver(frame_ix), isolate);
312 910164 : function_ = handle(array->Function(frame_ix), isolate);
313 910164 : code_ = handle(array->Code(frame_ix), isolate);
314 910164 : offset_ = array->Offset(frame_ix)->value();
315 :
316 910164 : const int flags = array->Flags(frame_ix)->value();
317 455082 : is_constructor_ = (flags & FrameArray::kIsConstructor) != 0;
318 455082 : is_strict_ = (flags & FrameArray::kIsStrict) != 0;
319 455082 : is_async_ = (flags & FrameArray::kIsAsync) != 0;
320 455082 : is_promise_all_ = (flags & FrameArray::kIsPromiseAll) != 0;
321 455082 : }
322 :
323 0 : JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
324 : Handle<JSFunction> function,
325 : Handle<AbstractCode> code, int offset)
326 : : StackFrameBase(isolate),
327 : receiver_(receiver),
328 : function_(function),
329 : code_(code),
330 : offset_(offset),
331 : is_async_(false),
332 : is_constructor_(false),
333 0 : is_strict_(false) {}
334 :
335 10690 : Handle<Object> JSStackFrame::GetFunction() const {
336 10690 : return Handle<Object>::cast(function_);
337 : }
338 :
339 64315 : Handle<Object> JSStackFrame::GetFileName() {
340 64333 : if (!HasScript()) return isolate_->factory()->null_value();
341 128594 : return handle(GetScript()->name(), isolate_);
342 : }
343 :
344 110787 : Handle<Object> JSStackFrame::GetFunctionName() {
345 110787 : Handle<String> result = JSFunction::GetName(function_);
346 110787 : if (result->length() != 0) return result;
347 :
348 45471 : if (HasScript() &&
349 60574 : GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
350 1804 : return isolate_->factory()->eval_string();
351 : }
352 28510 : return isolate_->factory()->null_value();
353 : }
354 :
355 : namespace {
356 :
357 13664 : bool CheckMethodName(Isolate* isolate, Handle<JSReceiver> receiver,
358 : Handle<Name> name, Handle<JSFunction> fun,
359 : LookupIterator::Configuration config) {
360 : LookupIterator iter =
361 13664 : LookupIterator::PropertyOrElement(isolate, receiver, name, config);
362 13664 : if (iter.state() == LookupIterator::DATA) {
363 24442 : return iter.GetDataValue().is_identical_to(fun);
364 1443 : } else if (iter.state() == LookupIterator::ACCESSOR) {
365 387 : Handle<Object> accessors = iter.GetAccessors();
366 774 : if (accessors->IsAccessorPair()) {
367 387 : Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors);
368 639 : return pair->getter() == *fun || pair->setter() == *fun;
369 : }
370 : }
371 : return false;
372 : }
373 :
374 68435 : Handle<Object> ScriptNameOrSourceUrl(Handle<Script> script, Isolate* isolate) {
375 68435 : Object name_or_url = script->source_url();
376 135144 : if (!name_or_url->IsString()) name_or_url = script->name();
377 68435 : return handle(name_or_url, isolate);
378 : }
379 :
380 : } // namespace
381 :
382 69829 : Handle<Object> JSStackFrame::GetScriptNameOrSourceUrl() {
383 71311 : if (!HasScript()) return isolate_->factory()->null_value();
384 68347 : return ScriptNameOrSourceUrl(GetScript(), isolate_);
385 : }
386 :
387 9720 : Handle<Object> JSStackFrame::GetMethodName() {
388 29160 : if (receiver_->IsNullOrUndefined(isolate_)) {
389 0 : return isolate_->factory()->null_value();
390 : }
391 :
392 : Handle<JSReceiver> receiver;
393 19440 : if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
394 : DCHECK(isolate_->has_pending_exception());
395 0 : isolate_->clear_pending_exception();
396 0 : isolate_->set_external_caught_exception(false);
397 0 : return isolate_->factory()->null_value();
398 : }
399 :
400 29160 : Handle<String> name(function_->shared()->Name(), isolate_);
401 :
402 : // The static initializer function is not a method, so don't add a
403 : // class name, just return the function name.
404 9720 : if (name->IsUtf8EqualTo(CStrVector("<static_fields_initializer>"), true)) {
405 14 : return name;
406 : }
407 :
408 : // ES2015 gives getters and setters name prefixes which must
409 : // be stripped to find the property name.
410 29046 : if (name->IsUtf8EqualTo(CStrVector("get "), true) ||
411 19340 : name->IsUtf8EqualTo(CStrVector("set "), true)) {
412 81 : name = isolate_->factory()->NewProperSubString(name, 4, name->length());
413 : }
414 19412 : if (CheckMethodName(isolate_, receiver, name, function_,
415 19412 : LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) {
416 8641 : return name;
417 : }
418 :
419 1065 : HandleScope outer_scope(isolate_);
420 : Handle<Object> result;
421 4860 : for (PrototypeIterator iter(isolate_, receiver, kStartAtReceiver);
422 2730 : !iter.IsAtEnd(); iter.Advance()) {
423 : Handle<Object> current = PrototypeIterator::GetCurrent(iter);
424 5478 : if (!current->IsJSObject()) break;
425 2739 : Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
426 5478 : if (current_obj->IsAccessCheckNeeded()) break;
427 : Handle<FixedArray> keys =
428 2739 : KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, current_obj);
429 13376 : for (int i = 0; i < keys->length(); i++) {
430 3958 : HandleScope inner_scope(isolate_);
431 7916 : if (!keys->get(i)->IsName()) continue;
432 3958 : Handle<Name> name_key(Name::cast(keys->get(i)), isolate_);
433 3958 : if (!CheckMethodName(isolate_, current_obj, name_key, function_,
434 3958 : LookupIterator::OWN_SKIP_INTERCEPTOR))
435 : continue;
436 : // Return null in case of duplicates to avoid confusion.
437 397 : if (!result.is_null()) return isolate_->factory()->null_value();
438 379 : result = inner_scope.CloseAndEscape(name_key);
439 : }
440 : }
441 :
442 1056 : if (!result.is_null()) return outer_scope.CloseAndEscape(result);
443 1372 : return isolate_->factory()->null_value();
444 : }
445 :
446 10162 : Handle<Object> JSStackFrame::GetTypeName() {
447 : // TODO(jgruber): Check for strict/constructor here as in
448 : // CallSitePrototypeGetThis.
449 :
450 30486 : if (receiver_->IsNullOrUndefined(isolate_)) {
451 36 : return isolate_->factory()->null_value();
452 20288 : } else if (receiver_->IsJSProxy()) {
453 18 : return isolate_->factory()->Proxy_string();
454 : }
455 :
456 : Handle<JSReceiver> receiver;
457 20270 : if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
458 : DCHECK(isolate_->has_pending_exception());
459 0 : isolate_->clear_pending_exception();
460 0 : isolate_->set_external_caught_exception(false);
461 0 : return isolate_->factory()->null_value();
462 : }
463 :
464 10135 : return JSReceiver::GetConstructorName(receiver);
465 : }
466 :
467 100868 : int JSStackFrame::GetLineNumber() {
468 : DCHECK_LE(0, GetPosition());
469 100868 : if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
470 : return kNone;
471 : }
472 :
473 99225 : int JSStackFrame::GetColumnNumber() {
474 : DCHECK_LE(0, GetPosition());
475 99225 : if (HasScript()) {
476 99207 : return Script::GetColumnNumber(GetScript(), GetPosition()) + 1;
477 : }
478 : return kNone;
479 : }
480 :
481 27 : int JSStackFrame::GetPromiseIndex() const {
482 27 : return is_promise_all_ ? offset_ : kNone;
483 : }
484 :
485 90330 : bool JSStackFrame::IsNative() {
486 179160 : return HasScript() && GetScript()->type() == Script::TYPE_NATIVE;
487 : }
488 :
489 90375 : bool JSStackFrame::IsToplevel() {
490 203990 : return receiver_->IsJSGlobalProxy() || receiver_->IsNullOrUndefined(isolate_);
491 : }
492 :
493 : namespace {
494 :
495 138594 : bool IsNonEmptyString(Handle<Object> object) {
496 403459 : return (object->IsString() && String::cast(*object)->length() > 0);
497 : }
498 :
499 59623 : void AppendFileLocation(Isolate* isolate, StackFrameBase* call_site,
500 : IncrementalStringBuilder* builder) {
501 59623 : if (call_site->IsNative()) {
502 : builder->AppendCString("native");
503 59623 : return;
504 : }
505 :
506 59623 : Handle<Object> file_name = call_site->GetScriptNameOrSourceUrl();
507 119246 : if (!file_name->IsString() && call_site->IsEval()) {
508 751 : Handle<Object> eval_origin = call_site->GetEvalOrigin();
509 : DCHECK(eval_origin->IsString());
510 751 : builder->AppendString(Handle<String>::cast(eval_origin));
511 : builder->AppendCString(", "); // Expecting source position to follow.
512 : }
513 :
514 59623 : if (IsNonEmptyString(file_name)) {
515 56375 : builder->AppendString(Handle<String>::cast(file_name));
516 : } else {
517 : // Source code does not originate from a file and is not native, but we
518 : // can still get the source position inside the source string, e.g. in
519 : // an eval string.
520 : builder->AppendCString("<anonymous>");
521 : }
522 :
523 59623 : int line_number = call_site->GetLineNumber();
524 59623 : if (line_number != StackFrameBase::kNone) {
525 : builder->AppendCharacter(':');
526 : Handle<String> line_string = isolate->factory()->NumberToString(
527 116282 : handle(Smi::FromInt(line_number), isolate), isolate);
528 58141 : builder->AppendString(line_string);
529 :
530 58141 : int column_number = call_site->GetColumnNumber();
531 58141 : if (column_number != StackFrameBase::kNone) {
532 : builder->AppendCharacter(':');
533 : Handle<String> column_string = isolate->factory()->NumberToString(
534 58141 : handle(Smi::FromInt(column_number), isolate), isolate);
535 58141 : builder->AppendString(column_string);
536 : }
537 : }
538 : }
539 :
540 9535 : int StringIndexOf(Isolate* isolate, Handle<String> subject,
541 : Handle<String> pattern) {
542 9535 : if (pattern->length() > subject->length()) return -1;
543 6316 : return String::IndexOf(isolate, subject, pattern, 0);
544 : }
545 :
546 : // Returns true iff
547 : // 1. the subject ends with '.' + pattern, or
548 : // 2. subject == pattern.
549 8926 : bool StringEndsWithMethodName(Isolate* isolate, Handle<String> subject,
550 : Handle<String> pattern) {
551 8926 : if (String::Equals(isolate, subject, pattern)) return true;
552 :
553 379 : FlatStringReader subject_reader(isolate, String::Flatten(isolate, subject));
554 379 : FlatStringReader pattern_reader(isolate, String::Flatten(isolate, pattern));
555 :
556 379 : int pattern_index = pattern_reader.length() - 1;
557 379 : int subject_index = subject_reader.length() - 1;
558 3610 : for (int i = 0; i <= pattern_reader.length(); i++) { // Iterate over len + 1.
559 3402 : if (subject_index < 0) {
560 : return false;
561 : }
562 :
563 : const uc32 subject_char = subject_reader.Get(subject_index);
564 3402 : if (i == pattern_reader.length()) {
565 271 : if (subject_char != '.') return false;
566 3131 : } else if (subject_char != pattern_reader.Get(pattern_index)) {
567 : return false;
568 : }
569 :
570 3231 : pattern_index--;
571 3231 : subject_index--;
572 : }
573 :
574 : return true;
575 : }
576 :
577 9630 : void AppendMethodCall(Isolate* isolate, JSStackFrame* call_site,
578 : IncrementalStringBuilder* builder) {
579 9630 : Handle<Object> type_name = call_site->GetTypeName();
580 9630 : Handle<Object> method_name = call_site->GetMethodName();
581 9630 : Handle<Object> function_name = call_site->GetFunctionName();
582 :
583 9630 : if (IsNonEmptyString(function_name)) {
584 9535 : Handle<String> function_string = Handle<String>::cast(function_name);
585 9535 : if (IsNonEmptyString(type_name)) {
586 9535 : Handle<String> type_string = Handle<String>::cast(type_name);
587 : bool starts_with_type_name =
588 9535 : (StringIndexOf(isolate, function_string, type_string) == 0);
589 9535 : if (!starts_with_type_name) {
590 9467 : builder->AppendString(type_string);
591 : builder->AppendCharacter('.');
592 : }
593 : }
594 9535 : builder->AppendString(function_string);
595 :
596 9535 : if (IsNonEmptyString(method_name)) {
597 8926 : Handle<String> method_string = Handle<String>::cast(method_name);
598 8926 : if (!StringEndsWithMethodName(isolate, function_string, method_string)) {
599 : builder->AppendCString(" [as ");
600 171 : builder->AppendString(method_string);
601 : builder->AppendCharacter(']');
602 : }
603 : }
604 : } else {
605 95 : if (IsNonEmptyString(type_name)) {
606 95 : builder->AppendString(Handle<String>::cast(type_name));
607 : builder->AppendCharacter('.');
608 : }
609 95 : if (IsNonEmptyString(method_name)) {
610 36 : builder->AppendString(Handle<String>::cast(method_name));
611 : } else {
612 : builder->AppendCString("<anonymous>");
613 : }
614 : }
615 9630 : }
616 :
617 : } // namespace
618 :
619 59580 : MaybeHandle<String> JSStackFrame::ToString() {
620 59580 : IncrementalStringBuilder builder(isolate_);
621 :
622 59580 : Handle<Object> function_name = GetFunctionName();
623 :
624 59580 : const bool is_toplevel = IsToplevel();
625 59580 : const bool is_async = IsAsync();
626 59580 : const bool is_promise_all = IsPromiseAll();
627 59580 : const bool is_constructor = IsConstructor();
628 59580 : const bool is_method_call = !(is_toplevel || is_constructor);
629 :
630 59580 : if (is_async) {
631 : builder.AppendCString("async ");
632 : }
633 59580 : if (is_promise_all) {
634 : // For `Promise.all(iterable)` frames we interpret the {offset_}
635 : // as the element index into `iterable` where the error occurred.
636 : builder.AppendCString("Promise.all (index ");
637 : Handle<String> index_string = isolate_->factory()->NumberToString(
638 90 : handle(Smi::FromInt(offset_), isolate_), isolate_);
639 45 : builder.AppendString(index_string);
640 : builder.AppendCString(")");
641 45 : return builder.Finish();
642 : }
643 59535 : if (is_method_call) {
644 9630 : AppendMethodCall(isolate_, this, &builder);
645 49905 : } else if (is_constructor) {
646 : builder.AppendCString("new ");
647 712 : if (IsNonEmptyString(function_name)) {
648 712 : builder.AppendString(Handle<String>::cast(function_name));
649 : } else {
650 : builder.AppendCString("<anonymous>");
651 : }
652 49193 : } else if (IsNonEmptyString(function_name)) {
653 39989 : builder.AppendString(Handle<String>::cast(function_name));
654 : } else {
655 9204 : AppendFileLocation(isolate_, this, &builder);
656 9204 : return builder.Finish();
657 : }
658 :
659 : builder.AppendCString(" (");
660 50331 : AppendFileLocation(isolate_, this, &builder);
661 : builder.AppendCString(")");
662 :
663 50331 : return builder.Finish();
664 : }
665 :
666 397150 : int JSStackFrame::GetPosition() const { return code_->SourcePosition(offset_); }
667 :
668 525062 : bool JSStackFrame::HasScript() const {
669 1050124 : return function_->shared()->script()->IsScript();
670 : }
671 :
672 518999 : Handle<Script> JSStackFrame::GetScript() const {
673 1556997 : return handle(Script::cast(function_->shared()->script()), isolate_);
674 : }
675 :
676 5996 : void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
677 : int frame_ix) {
678 : // This function is called for compiled and interpreted wasm frames, and for
679 : // asm.js->wasm frames.
680 : DCHECK(array->IsWasmFrame(frame_ix) ||
681 : array->IsWasmInterpretedFrame(frame_ix) ||
682 : array->IsAsmJsWasmFrame(frame_ix));
683 5996 : isolate_ = isolate;
684 11992 : wasm_instance_ = handle(array->WasmInstance(frame_ix), isolate);
685 11992 : wasm_func_index_ = array->WasmFunctionIndex(frame_ix)->value();
686 11992 : if (array->IsWasmInterpretedFrame(frame_ix)) {
687 3224 : code_ = nullptr;
688 : } else {
689 : code_ = reinterpret_cast<wasm::WasmCode*>(
690 5544 : array->WasmCodeObject(frame_ix)->foreign_address());
691 : }
692 11992 : offset_ = array->Offset(frame_ix)->value();
693 5996 : }
694 :
695 0 : Handle<Object> WasmStackFrame::GetReceiver() const { return wasm_instance_; }
696 :
697 0 : Handle<Object> WasmStackFrame::GetFunction() const {
698 0 : return handle(Smi::FromInt(wasm_func_index_), isolate_);
699 : }
700 :
701 908 : Handle<Object> WasmStackFrame::GetFunctionName() {
702 : Handle<Object> name;
703 : Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
704 2724 : isolate_);
705 908 : if (!WasmModuleObject::GetFunctionNameOrNull(isolate_, module_object,
706 908 : wasm_func_index_)
707 1816 : .ToHandle(&name)) {
708 16 : name = isolate_->factory()->null_value();
709 : }
710 908 : return name;
711 : }
712 :
713 596 : MaybeHandle<String> WasmStackFrame::ToString() {
714 596 : IncrementalStringBuilder builder(isolate_);
715 :
716 : Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
717 1788 : isolate_);
718 : MaybeHandle<String> module_name =
719 596 : WasmModuleObject::GetModuleNameOrNull(isolate_, module_object);
720 : MaybeHandle<String> function_name = WasmModuleObject::GetFunctionNameOrNull(
721 596 : isolate_, module_object, wasm_func_index_);
722 596 : bool has_name = !module_name.is_null() || !function_name.is_null();
723 596 : if (has_name) {
724 568 : if (module_name.is_null()) {
725 544 : builder.AppendString(function_name.ToHandleChecked());
726 : } else {
727 24 : builder.AppendString(module_name.ToHandleChecked());
728 24 : if (!function_name.is_null()) {
729 : builder.AppendCString(".");
730 12 : builder.AppendString(function_name.ToHandleChecked());
731 : }
732 : }
733 : builder.AppendCString(" (");
734 : }
735 :
736 : builder.AppendCString("wasm-function[");
737 :
738 : char buffer[16];
739 596 : SNPrintF(ArrayVector(buffer), "%u]", wasm_func_index_);
740 : builder.AppendCString(buffer);
741 :
742 596 : SNPrintF(ArrayVector(buffer), ":%d", GetPosition());
743 : builder.AppendCString(buffer);
744 :
745 596 : if (has_name) builder.AppendCString(")");
746 :
747 596 : return builder.Finish();
748 : }
749 :
750 1240 : int WasmStackFrame::GetPosition() const {
751 : return IsInterpreted()
752 : ? offset_
753 : : FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(
754 1240 : code_, offset_);
755 : }
756 :
757 0 : Handle<Object> WasmStackFrame::Null() const {
758 960 : return isolate_->factory()->null_value();
759 : }
760 :
761 1016 : bool WasmStackFrame::HasScript() const { return true; }
762 :
763 1016 : Handle<Script> WasmStackFrame::GetScript() const {
764 3048 : return handle(wasm_instance_->module_object()->script(), isolate_);
765 : }
766 :
767 1256 : void AsmJsWasmStackFrame::FromFrameArray(Isolate* isolate,
768 : Handle<FrameArray> array,
769 : int frame_ix) {
770 : DCHECK(array->IsAsmJsWasmFrame(frame_ix));
771 1256 : WasmStackFrame::FromFrameArray(isolate, array, frame_ix);
772 : is_at_number_conversion_ =
773 2512 : array->Flags(frame_ix)->value() & FrameArray::kAsmJsAtNumberConversion;
774 1256 : }
775 :
776 208 : Handle<Object> AsmJsWasmStackFrame::GetReceiver() const {
777 208 : return isolate_->global_proxy();
778 : }
779 :
780 0 : Handle<Object> AsmJsWasmStackFrame::GetFunction() const {
781 : // TODO(clemensh): Return lazily created JSFunction.
782 0 : return Null();
783 : }
784 :
785 224 : Handle<Object> AsmJsWasmStackFrame::GetFileName() {
786 672 : Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
787 : DCHECK(script->IsUserJavaScript());
788 448 : return handle(script->name(), isolate_);
789 : }
790 :
791 88 : Handle<Object> AsmJsWasmStackFrame::GetScriptNameOrSourceUrl() {
792 264 : Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
793 : DCHECK_EQ(Script::TYPE_NORMAL, script->type());
794 88 : return ScriptNameOrSourceUrl(script, isolate_);
795 : }
796 :
797 656 : int AsmJsWasmStackFrame::GetPosition() const {
798 : DCHECK_LE(0, offset_);
799 : int byte_offset =
800 : FrameSummary::WasmCompiledFrameSummary::GetWasmSourcePosition(code_,
801 656 : offset_);
802 : Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
803 1968 : isolate_);
804 : DCHECK_LE(0, byte_offset);
805 : return WasmModuleObject::GetSourcePosition(module_object, wasm_func_index_,
806 : static_cast<uint32_t>(byte_offset),
807 656 : is_at_number_conversion_);
808 : }
809 :
810 312 : int AsmJsWasmStackFrame::GetLineNumber() {
811 : DCHECK_LE(0, GetPosition());
812 936 : Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
813 : DCHECK(script->IsUserJavaScript());
814 312 : return Script::GetLineNumber(script, GetPosition()) + 1;
815 : }
816 :
817 344 : int AsmJsWasmStackFrame::GetColumnNumber() {
818 : DCHECK_LE(0, GetPosition());
819 1032 : Handle<Script> script(wasm_instance_->module_object()->script(), isolate_);
820 : DCHECK(script->IsUserJavaScript());
821 344 : return Script::GetColumnNumber(script, GetPosition()) + 1;
822 : }
823 :
824 88 : MaybeHandle<String> AsmJsWasmStackFrame::ToString() {
825 : // The string should look exactly as the respective javascript frame string.
826 : // Keep this method in line to JSStackFrame::ToString().
827 :
828 88 : IncrementalStringBuilder builder(isolate_);
829 :
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 builder.Finish();
842 : }
843 :
844 316077 : FrameArrayIterator::FrameArrayIterator(Isolate* isolate,
845 : Handle<FrameArray> array, int frame_ix)
846 641857 : : isolate_(isolate), array_(array), frame_ix_(frame_ix) {}
847 :
848 69244 : bool FrameArrayIterator::HasFrame() const {
849 138488 : return (frame_ix_ < array_->FrameCount());
850 : }
851 :
852 59541 : void FrameArrayIterator::Advance() { frame_ix_++; }
853 :
854 461078 : StackFrameBase* FrameArrayIterator::Frame() {
855 : DCHECK(HasFrame());
856 1383234 : const int flags = array_->Flags(frame_ix_)->value();
857 : int flag_mask = FrameArray::kIsWasmFrame |
858 : FrameArray::kIsWasmInterpretedFrame |
859 : FrameArray::kIsAsmJsWasmFrame;
860 461078 : switch (flags & flag_mask) {
861 : case 0:
862 : // JavaScript Frame.
863 455082 : js_frame_.FromFrameArray(isolate_, array_, frame_ix_);
864 455082 : 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 48476 : MaybeHandle<Object> ConstructCallSite(Isolate* isolate,
882 : Handle<FrameArray> frame_array,
883 : int frame_index) {
884 : Handle<JSFunction> target =
885 145428 : handle(isolate->native_context()->callsite_function(), isolate);
886 :
887 : Handle<JSObject> obj;
888 96952 : 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 96952 : 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 96952 : RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
900 : obj, key, value, DONT_ENUM),
901 : Object);
902 :
903 48476 : return obj;
904 : }
905 :
906 : // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into
907 : // a JSArray of JSCallSite objects.
908 5374 : MaybeHandle<JSArray> GetStackFrames(Isolate* isolate,
909 : Handle<FrameArray> elems) {
910 5374 : const int frame_count = elems->FrameCount();
911 :
912 5374 : Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count);
913 53850 : for (int i = 0; i < frame_count; i++) {
914 : Handle<Object> site;
915 96952 : ASSIGN_RETURN_ON_EXCEPTION(isolate, site,
916 : ConstructCallSite(isolate, elems, i), JSArray);
917 48476 : frames->set(i, *site);
918 : }
919 :
920 5374 : return isolate->factory()->NewJSArrayWithElements(frames);
921 : }
922 :
923 9703 : MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
924 : IncrementalStringBuilder* builder) {
925 : MaybeHandle<String> err_str =
926 9703 : ErrorUtils::ToString(isolate, Handle<Object>::cast(error));
927 9703 : 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 0 : 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 0 : 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 9703 : builder->AppendString(err_str.ToHandleChecked());
952 : }
953 :
954 9703 : 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 30154 : MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
976 : Handle<JSObject> error,
977 : Handle<Object> raw_stack) {
978 : DCHECK(raw_stack->IsJSArray());
979 15077 : Handle<JSArray> raw_stack_array = Handle<JSArray>::cast(raw_stack);
980 :
981 : DCHECK(raw_stack_array->elements()->IsFixedArray());
982 30154 : Handle<FrameArray> elems(FrameArray::cast(raw_stack_array->elements()),
983 30154 : isolate);
984 :
985 : const bool in_recursion = isolate->formatting_stack_trace();
986 15077 : if (!in_recursion) {
987 15050 : 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 15038 : 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 30076 : ASSIGN_RETURN_ON_EXCEPTION(
1010 : isolate, prepare_stack_trace,
1011 : JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"),
1012 : Object);
1013 :
1014 30076 : if (prepare_stack_trace->IsJSFunction()) {
1015 : PrepareStackTraceScope scope(isolate);
1016 :
1017 5362 : isolate->CountUsage(v8::Isolate::kErrorPrepareStackTrace);
1018 :
1019 : Handle<JSArray> sites;
1020 10724 : ASSIGN_RETURN_ON_EXCEPTION(isolate, sites,
1021 : GetStackFrames(isolate, elems), Object);
1022 :
1023 : const int argc = 2;
1024 : ScopedVector<Handle<Object>> argv(argc);
1025 5362 : argv[0] = error;
1026 5362 : argv[1] = sites;
1027 :
1028 : Handle<Object> result;
1029 :
1030 10724 : ASSIGN_RETURN_ON_EXCEPTION(
1031 : isolate, result,
1032 : Execution::Call(isolate, prepare_stack_trace, global_error, argc,
1033 : argv.start()),
1034 : Object);
1035 :
1036 5270 : return result;
1037 : }
1038 : }
1039 : }
1040 :
1041 : // Otherwise, run our internal formatting logic.
1042 :
1043 9703 : IncrementalStringBuilder builder(isolate);
1044 :
1045 19406 : RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder),
1046 : Object);
1047 :
1048 69244 : for (FrameArrayIterator it(isolate, elems); it.HasFrame(); it.Advance()) {
1049 : builder.AppendCString("\n at ");
1050 :
1051 59541 : StackFrameBase* frame = it.Frame();
1052 59541 : MaybeHandle<String> maybe_frame_string = frame->ToString();
1053 59541 : if (maybe_frame_string.is_null()) {
1054 : // CallSite.toString threw. Try to return a string representation of the
1055 : // thrown exception instead.
1056 :
1057 : DCHECK(isolate->has_pending_exception());
1058 : Handle<Object> pending_exception =
1059 0 : handle(isolate->pending_exception(), isolate);
1060 0 : isolate->clear_pending_exception();
1061 : isolate->set_external_caught_exception(false);
1062 :
1063 0 : maybe_frame_string = ErrorUtils::ToString(isolate, pending_exception);
1064 0 : if (maybe_frame_string.is_null()) {
1065 : // Formatting the thrown exception threw again, give up.
1066 :
1067 : builder.AppendCString("<error>");
1068 : } else {
1069 : // Formatted thrown exception successfully, append it.
1070 : builder.AppendCString("<error: ");
1071 0 : builder.AppendString(maybe_frame_string.ToHandleChecked());
1072 : builder.AppendCString("<error>");
1073 : }
1074 : } else {
1075 : // CallSite.toString completed without throwing.
1076 59541 : builder.AppendString(maybe_frame_string.ToHandleChecked());
1077 : }
1078 : }
1079 :
1080 9703 : return builder.Finish();
1081 : }
1082 :
1083 6715 : Handle<String> MessageFormatter::FormatMessage(Isolate* isolate,
1084 : MessageTemplate index,
1085 : Handle<Object> arg) {
1086 : Factory* factory = isolate->factory();
1087 6715 : Handle<String> result_string = Object::NoSideEffectsToString(isolate, arg);
1088 : MaybeHandle<String> maybe_result_string = MessageFormatter::FormatMessage(
1089 : isolate, index, result_string, factory->empty_string(),
1090 6715 : factory->empty_string());
1091 6715 : if (!maybe_result_string.ToHandle(&result_string)) {
1092 : DCHECK(isolate->has_pending_exception());
1093 0 : isolate->clear_pending_exception();
1094 0 : return factory->InternalizeOneByteString(StaticCharVector("<error>"));
1095 : }
1096 : // A string that has been obtained from JS code in this way is
1097 : // likely to be a complicated ConsString of some sort. We flatten it
1098 : // here to improve the efficiency of converting it to a C string and
1099 : // other operations that are likely to take place (see GetLocalizedMessage
1100 : // for example).
1101 6715 : return String::Flatten(isolate, result_string);
1102 : }
1103 :
1104 1207753 : const char* MessageFormatter::TemplateString(MessageTemplate index) {
1105 1207753 : switch (index) {
1106 : #define CASE(NAME, STRING) \
1107 : case MessageTemplate::k##NAME: \
1108 : return STRING;
1109 60 : MESSAGE_TEMPLATES(CASE)
1110 : #undef CASE
1111 : case MessageTemplate::kLastMessage:
1112 : default:
1113 0 : return nullptr;
1114 : }
1115 : }
1116 :
1117 1158738 : MaybeHandle<String> MessageFormatter::FormatMessage(Isolate* isolate,
1118 : MessageTemplate index,
1119 : Handle<String> arg0,
1120 : Handle<String> arg1,
1121 : Handle<String> arg2) {
1122 1158738 : const char* template_string = TemplateString(index);
1123 1158738 : if (template_string == nullptr) {
1124 0 : isolate->ThrowIllegalOperation();
1125 0 : return MaybeHandle<String>();
1126 : }
1127 :
1128 1158738 : IncrementalStringBuilder builder(isolate);
1129 :
1130 : unsigned int i = 0;
1131 1158738 : Handle<String> args[] = {arg0, arg1, arg2};
1132 42013629 : for (const char* c = template_string; *c != '\0'; c++) {
1133 40854891 : if (*c == '%') {
1134 : // %% results in verbatim %.
1135 759290 : if (*(c + 1) == '%') {
1136 0 : c++;
1137 : builder.AppendCharacter('%');
1138 : } else {
1139 : DCHECK(i < arraysize(args));
1140 759290 : Handle<String> arg = args[i++];
1141 759290 : builder.AppendString(arg);
1142 : }
1143 : } else {
1144 40095601 : builder.AppendCharacter(*c);
1145 : }
1146 : }
1147 :
1148 1158738 : return builder.Finish();
1149 : }
1150 :
1151 1251799 : MaybeHandle<Object> ErrorUtils::Construct(
1152 : Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
1153 : Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
1154 : bool suppress_detailed_trace) {
1155 : // 1. If NewTarget is undefined, let newTarget be the active function object,
1156 : // else let newTarget be NewTarget.
1157 :
1158 : Handle<JSReceiver> new_target_recv =
1159 2503598 : new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
1160 1251799 : : Handle<JSReceiver>::cast(target);
1161 :
1162 : // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
1163 : // « [[ErrorData]] »).
1164 : Handle<JSObject> err;
1165 2503598 : ASSIGN_RETURN_ON_EXCEPTION(
1166 : isolate, err,
1167 : JSObject::New(target, new_target_recv, Handle<AllocationSite>::null()),
1168 : Object);
1169 :
1170 : // 3. If message is not undefined, then
1171 : // a. Let msg be ? ToString(message).
1172 : // b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
1173 : // true, [[Enumerable]]: false, [[Configurable]]: true}.
1174 : // c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
1175 : // 4. Return O.
1176 :
1177 2503598 : if (!message->IsUndefined(isolate)) {
1178 : Handle<String> msg_string;
1179 2480146 : ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
1180 : Object::ToString(isolate, message), Object);
1181 2480128 : RETURN_ON_EXCEPTION(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
1182 : err, isolate->factory()->message_string(),
1183 : msg_string, DONT_ENUM),
1184 : Object);
1185 : }
1186 :
1187 : // Optionally capture a more detailed stack trace for the message.
1188 1251790 : if (!suppress_detailed_trace) {
1189 2406360 : RETURN_ON_EXCEPTION(isolate, isolate->CaptureAndSetDetailedStackTrace(err),
1190 : Object);
1191 : }
1192 :
1193 : // Capture a simple stack trace for the stack property.
1194 2503580 : RETURN_ON_EXCEPTION(isolate,
1195 : isolate->CaptureAndSetSimpleStackTrace(err, mode, caller),
1196 : Object);
1197 :
1198 1251790 : return err;
1199 : }
1200 :
1201 : namespace {
1202 :
1203 607318 : MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
1204 : Handle<JSReceiver> recv,
1205 : Handle<String> key,
1206 : Handle<String> default_str) {
1207 : Handle<Object> obj;
1208 1214636 : ASSIGN_RETURN_ON_EXCEPTION(isolate, obj,
1209 : JSObject::GetProperty(isolate, recv, key), String);
1210 :
1211 : Handle<String> str;
1212 1203106 : if (obj->IsUndefined(isolate)) {
1213 162 : str = default_str;
1214 : } else {
1215 1202782 : ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
1216 : String);
1217 : }
1218 :
1219 594559 : return str;
1220 : }
1221 :
1222 : } // namespace
1223 :
1224 : // ES6 section 19.5.3.4 Error.prototype.toString ( )
1225 307354 : MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
1226 : Handle<Object> receiver) {
1227 : // 1. Let O be the this value.
1228 : // 2. If Type(O) is not Object, throw a TypeError exception.
1229 614708 : if (!receiver->IsJSReceiver()) {
1230 : return isolate->Throw<String>(isolate->factory()->NewTypeError(
1231 : MessageTemplate::kIncompatibleMethodReceiver,
1232 : isolate->factory()->NewStringFromAsciiChecked(
1233 : "Error.prototype.toString"),
1234 396 : receiver));
1235 : }
1236 307156 : Handle<JSReceiver> recv = Handle<JSReceiver>::cast(receiver);
1237 :
1238 : // 3. Let name be ? Get(O, "name").
1239 : // 4. If name is undefined, let name be "Error"; otherwise let name be
1240 : // ? ToString(name).
1241 307156 : Handle<String> name_key = isolate->factory()->name_string();
1242 307156 : Handle<String> name_default = isolate->factory()->Error_string();
1243 : Handle<String> name;
1244 614312 : ASSIGN_RETURN_ON_EXCEPTION(
1245 : isolate, name,
1246 : GetStringPropertyOrDefault(isolate, recv, name_key, name_default),
1247 : String);
1248 :
1249 : // 5. Let msg be ? Get(O, "message").
1250 : // 6. If msg is undefined, let msg be the empty String; otherwise let msg be
1251 : // ? ToString(msg).
1252 300162 : Handle<String> msg_key = isolate->factory()->message_string();
1253 300162 : Handle<String> msg_default = isolate->factory()->empty_string();
1254 : Handle<String> msg;
1255 600324 : ASSIGN_RETURN_ON_EXCEPTION(
1256 : isolate, msg,
1257 : GetStringPropertyOrDefault(isolate, recv, msg_key, msg_default), String);
1258 :
1259 : // 7. If name is the empty String, return msg.
1260 : // 8. If msg is the empty String, return name.
1261 294397 : if (name->length() == 0) return msg;
1262 294334 : if (msg->length() == 0) return name;
1263 :
1264 : // 9. Return the result of concatenating name, the code unit 0x003A (COLON),
1265 : // the code unit 0x0020 (SPACE), and msg.
1266 291082 : IncrementalStringBuilder builder(isolate);
1267 291082 : builder.AppendString(name);
1268 : builder.AppendCString(": ");
1269 291082 : builder.AppendString(msg);
1270 :
1271 : Handle<String> result;
1272 582164 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
1273 291082 : return result;
1274 : }
1275 :
1276 : namespace {
1277 :
1278 1152018 : Handle<String> FormatMessage(Isolate* isolate, MessageTemplate index,
1279 : Handle<Object> arg0, Handle<Object> arg1,
1280 : Handle<Object> arg2) {
1281 1152018 : Handle<String> arg0_str = Object::NoSideEffectsToString(isolate, arg0);
1282 1152018 : Handle<String> arg1_str = Object::NoSideEffectsToString(isolate, arg1);
1283 1152018 : Handle<String> arg2_str = Object::NoSideEffectsToString(isolate, arg2);
1284 :
1285 2304036 : isolate->native_context()->IncrementErrorsThrown();
1286 :
1287 : Handle<String> msg;
1288 1152018 : if (!MessageFormatter::FormatMessage(isolate, index, arg0_str, arg1_str,
1289 : arg2_str)
1290 2304036 : .ToHandle(&msg)) {
1291 : DCHECK(isolate->has_pending_exception());
1292 18 : isolate->clear_pending_exception();
1293 : isolate->set_external_caught_exception(false);
1294 18 : return isolate->factory()->NewStringFromAsciiChecked("<error>");
1295 : }
1296 :
1297 1152000 : return msg;
1298 : }
1299 :
1300 : } // namespace
1301 :
1302 : // static
1303 1152018 : MaybeHandle<Object> ErrorUtils::MakeGenericError(
1304 : Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
1305 : Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
1306 : FrameSkipMode mode) {
1307 1152018 : if (FLAG_clear_exceptions_on_js_entry) {
1308 : // This function used to be implemented in JavaScript, and JSEntry
1309 : // clears any pending exceptions - so whenever we'd call this from C++,
1310 : // pending exceptions would be cleared. Preserve this behavior.
1311 0 : isolate->clear_pending_exception();
1312 : }
1313 :
1314 : DCHECK(mode != SKIP_UNTIL_SEEN);
1315 :
1316 : Handle<Object> no_caller;
1317 1152018 : Handle<String> msg = FormatMessage(isolate, index, arg0, arg1, arg2);
1318 : return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode,
1319 1152018 : no_caller, false);
1320 : }
1321 :
1322 : } // namespace internal
1323 178779 : } // namespace v8
|