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