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