• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/execution/messages.h"
6 
7 #include <memory>
8 
9 #include "src/api/api-inl.h"
10 #include "src/ast/ast.h"
11 #include "src/ast/prettyprinter.h"
12 #include "src/base/v8-fallthrough.h"
13 #include "src/execution/execution.h"
14 #include "src/execution/frames-inl.h"
15 #include "src/execution/frames.h"
16 #include "src/execution/isolate-inl.h"
17 #include "src/logging/counters.h"
18 #include "src/objects/foreign-inl.h"
19 #include "src/objects/frame-array-inl.h"
20 #include "src/objects/js-array-inl.h"
21 #include "src/objects/keys.h"
22 #include "src/objects/stack-frame-info-inl.h"
23 #include "src/objects/struct-inl.h"
24 #include "src/parsing/parse-info.h"
25 #include "src/parsing/parsing.h"
26 #include "src/roots/roots.h"
27 #include "src/strings/string-builder-inl.h"
28 #include "src/wasm/wasm-code-manager.h"
29 #include "src/wasm/wasm-objects.h"
30 
31 namespace v8 {
32 namespace internal {
33 
MessageLocation(Handle<Script> script,int start_pos,int end_pos)34 MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
35                                  int end_pos)
36     : script_(script),
37       start_pos_(start_pos),
38       end_pos_(end_pos),
39       bytecode_offset_(-1) {}
40 
MessageLocation(Handle<Script> script,int start_pos,int end_pos,Handle<SharedFunctionInfo> shared)41 MessageLocation::MessageLocation(Handle<Script> script, int start_pos,
42                                  int end_pos, Handle<SharedFunctionInfo> shared)
43     : script_(script),
44       start_pos_(start_pos),
45       end_pos_(end_pos),
46       bytecode_offset_(-1),
47       shared_(shared) {}
48 
MessageLocation(Handle<Script> script,Handle<SharedFunctionInfo> shared,int bytecode_offset)49 MessageLocation::MessageLocation(Handle<Script> script,
50                                  Handle<SharedFunctionInfo> shared,
51                                  int bytecode_offset)
52     : script_(script),
53       start_pos_(-1),
54       end_pos_(-1),
55       bytecode_offset_(bytecode_offset),
56       shared_(shared) {}
57 
MessageLocation()58 MessageLocation::MessageLocation()
59     : start_pos_(-1), end_pos_(-1), bytecode_offset_(-1) {}
60 
61 // If no message listeners have been registered this one is called
62 // by default.
DefaultMessageReport(Isolate * isolate,const MessageLocation * loc,Handle<Object> message_obj)63 void MessageHandler::DefaultMessageReport(Isolate* isolate,
64                                           const MessageLocation* loc,
65                                           Handle<Object> message_obj) {
66   std::unique_ptr<char[]> str = GetLocalizedMessage(isolate, message_obj);
67   if (loc == nullptr) {
68     PrintF("%s\n", str.get());
69   } else {
70     HandleScope scope(isolate);
71     Handle<Object> data(loc->script()->name(), isolate);
72     std::unique_ptr<char[]> data_str;
73     if (data->IsString())
74       data_str = Handle<String>::cast(data)->ToCString(DISALLOW_NULLS);
75     PrintF("%s:%i: %s\n", data_str.get() ? data_str.get() : "<unknown>",
76            loc->start_pos(), str.get());
77   }
78 }
79 
MakeMessageObject(Isolate * isolate,MessageTemplate message,const MessageLocation * location,Handle<Object> argument,Handle<FixedArray> stack_frames)80 Handle<JSMessageObject> MessageHandler::MakeMessageObject(
81     Isolate* isolate, MessageTemplate message, const MessageLocation* location,
82     Handle<Object> argument, Handle<FixedArray> stack_frames) {
83   Factory* factory = isolate->factory();
84 
85   int start = -1;
86   int end = -1;
87   int bytecode_offset = -1;
88   Handle<Script> script_handle = isolate->factory()->empty_script();
89   Handle<SharedFunctionInfo> shared_info;
90   if (location != nullptr && !FLAG_correctness_fuzzer_suppressions) {
91     start = location->start_pos();
92     end = location->end_pos();
93     script_handle = location->script();
94     bytecode_offset = location->bytecode_offset();
95     shared_info = location->shared();
96   }
97 
98   Handle<Object> stack_frames_handle =
99       stack_frames.is_null() ? Handle<Object>::cast(factory->undefined_value())
100                              : Handle<Object>::cast(stack_frames);
101 
102   Handle<JSMessageObject> message_obj = factory->NewJSMessageObject(
103       message, argument, start, end, shared_info, bytecode_offset,
104       script_handle, stack_frames_handle);
105 
106   return message_obj;
107 }
108 
ReportMessage(Isolate * isolate,const MessageLocation * loc,Handle<JSMessageObject> message)109 void MessageHandler::ReportMessage(Isolate* isolate, const MessageLocation* loc,
110                                    Handle<JSMessageObject> message) {
111   v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
112 
113   if (api_message_obj->ErrorLevel() == v8::Isolate::kMessageError) {
114     // We are calling into embedder's code which can throw exceptions.
115     // Thus we need to save current exception state, reset it to the clean one
116     // and ignore scheduled exceptions callbacks can throw.
117 
118     // We pass the exception object into the message handler callback though.
119     Object exception_object = ReadOnlyRoots(isolate).undefined_value();
120     if (isolate->has_pending_exception()) {
121       exception_object = isolate->pending_exception();
122     }
123     Handle<Object> exception(exception_object, isolate);
124 
125     Isolate::ExceptionScope exception_scope(isolate);
126     isolate->clear_pending_exception();
127     isolate->set_external_caught_exception(false);
128 
129     // Turn the exception on the message into a string if it is an object.
130     if (message->argument().IsJSObject()) {
131       HandleScope scope(isolate);
132       Handle<Object> argument(message->argument(), isolate);
133 
134       MaybeHandle<Object> maybe_stringified;
135       Handle<Object> stringified;
136       // Make sure we don't leak uncaught internally generated Error objects.
137       if (argument->IsJSError()) {
138         maybe_stringified = Object::NoSideEffectsToString(isolate, argument);
139       } else {
140         v8::TryCatch catcher(reinterpret_cast<v8::Isolate*>(isolate));
141         catcher.SetVerbose(false);
142         catcher.SetCaptureMessage(false);
143 
144         maybe_stringified = Object::ToString(isolate, argument);
145       }
146 
147       if (!maybe_stringified.ToHandle(&stringified)) {
148         DCHECK(isolate->has_pending_exception());
149         isolate->clear_pending_exception();
150         isolate->set_external_caught_exception(false);
151         stringified =
152             isolate->factory()->NewStringFromAsciiChecked("exception");
153       }
154       message->set_argument(*stringified);
155     }
156 
157     v8::Local<v8::Value> api_exception_obj = v8::Utils::ToLocal(exception);
158     ReportMessageNoExceptions(isolate, loc, message, api_exception_obj);
159   } else {
160     ReportMessageNoExceptions(isolate, loc, message, v8::Local<v8::Value>());
161   }
162 }
163 
ReportMessageNoExceptions(Isolate * isolate,const MessageLocation * loc,Handle<Object> message,v8::Local<v8::Value> api_exception_obj)164 void MessageHandler::ReportMessageNoExceptions(
165     Isolate* isolate, const MessageLocation* loc, Handle<Object> message,
166     v8::Local<v8::Value> api_exception_obj) {
167   v8::Local<v8::Message> api_message_obj = v8::Utils::MessageToLocal(message);
168   int error_level = api_message_obj->ErrorLevel();
169 
170   Handle<TemplateList> global_listeners =
171       isolate->factory()->message_listeners();
172   int global_length = global_listeners->length();
173   if (global_length == 0) {
174     DefaultMessageReport(isolate, loc, message);
175     if (isolate->has_scheduled_exception()) {
176       isolate->clear_scheduled_exception();
177     }
178   } else {
179     for (int i = 0; i < global_length; i++) {
180       HandleScope scope(isolate);
181       if (global_listeners->get(i).IsUndefined(isolate)) continue;
182       FixedArray listener = FixedArray::cast(global_listeners->get(i));
183       Foreign callback_obj = Foreign::cast(listener.get(0));
184       int32_t message_levels =
185           static_cast<int32_t>(Smi::ToInt(listener.get(2)));
186       if (!(message_levels & error_level)) {
187         continue;
188       }
189       v8::MessageCallback callback =
190           FUNCTION_CAST<v8::MessageCallback>(callback_obj.foreign_address());
191       Handle<Object> callback_data(listener.get(1), isolate);
192       {
193         RuntimeCallTimerScope timer(
194             isolate, RuntimeCallCounterId::kMessageListenerCallback);
195         // Do not allow exceptions to propagate.
196         v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
197         callback(api_message_obj, callback_data->IsUndefined(isolate)
198                                       ? api_exception_obj
199                                       : v8::Utils::ToLocal(callback_data));
200       }
201       if (isolate->has_scheduled_exception()) {
202         isolate->clear_scheduled_exception();
203       }
204     }
205   }
206 }
207 
GetMessage(Isolate * isolate,Handle<Object> data)208 Handle<String> MessageHandler::GetMessage(Isolate* isolate,
209                                           Handle<Object> data) {
210   Handle<JSMessageObject> message = Handle<JSMessageObject>::cast(data);
211   Handle<Object> arg = Handle<Object>(message->argument(), isolate);
212   return MessageFormatter::Format(isolate, message->type(), arg);
213 }
214 
GetLocalizedMessage(Isolate * isolate,Handle<Object> data)215 std::unique_ptr<char[]> MessageHandler::GetLocalizedMessage(
216     Isolate* isolate, Handle<Object> data) {
217   HandleScope scope(isolate);
218   return GetMessage(isolate, data)->ToCString(DISALLOW_NULLS);
219 }
220 
221 namespace {
222 
EvalFromFunctionName(Isolate * isolate,Handle<Script> script)223 Object EvalFromFunctionName(Isolate* isolate, Handle<Script> script) {
224   if (!script->has_eval_from_shared()) {
225     return ReadOnlyRoots(isolate).undefined_value();
226   }
227 
228   Handle<SharedFunctionInfo> shared(script->eval_from_shared(), isolate);
229   // Find the name of the function calling eval.
230   if (shared->Name().BooleanValue(isolate)) {
231     return shared->Name();
232   }
233 
234   return shared->inferred_name();
235 }
236 
FormatEvalOrigin(Isolate * isolate,Handle<Script> script)237 MaybeHandle<String> FormatEvalOrigin(Isolate* isolate, Handle<Script> script) {
238   Handle<Object> sourceURL(script->GetNameOrSourceURL(), isolate);
239   if (!sourceURL->IsUndefined(isolate)) {
240     DCHECK(sourceURL->IsString());
241     return Handle<String>::cast(sourceURL);
242   }
243 
244   IncrementalStringBuilder builder(isolate);
245   builder.AppendCString("eval at ");
246 
247   Handle<Object> eval_from_function_name =
248       handle(EvalFromFunctionName(isolate, script), isolate);
249   if (eval_from_function_name->BooleanValue(isolate)) {
250     Handle<String> str;
251     ASSIGN_RETURN_ON_EXCEPTION(
252         isolate, str, Object::ToString(isolate, eval_from_function_name),
253         String);
254     builder.AppendString(str);
255   } else {
256     builder.AppendCString("<anonymous>");
257   }
258 
259   if (script->has_eval_from_shared()) {
260     Handle<SharedFunctionInfo> eval_from_shared(script->eval_from_shared(),
261                                                 isolate);
262     if (eval_from_shared->script().IsScript()) {
263       Handle<Script> eval_from_script =
264           handle(Script::cast(eval_from_shared->script()), isolate);
265       builder.AppendCString(" (");
266       if (eval_from_script->compilation_type() ==
267           Script::COMPILATION_TYPE_EVAL) {
268         // Eval script originated from another eval.
269         Handle<String> str;
270         ASSIGN_RETURN_ON_EXCEPTION(
271             isolate, str, FormatEvalOrigin(isolate, eval_from_script), String);
272         builder.AppendString(str);
273       } else {
274         DCHECK(eval_from_script->compilation_type() !=
275                Script::COMPILATION_TYPE_EVAL);
276         // eval script originated from "real" source.
277         Handle<Object> name_obj = handle(eval_from_script->name(), isolate);
278         if (eval_from_script->name().IsString()) {
279           builder.AppendString(Handle<String>::cast(name_obj));
280 
281           Script::PositionInfo info;
282 
283           if (Script::GetPositionInfo(eval_from_script,
284                                       Script::GetEvalPosition(isolate, script),
285                                       &info, Script::NO_OFFSET)) {
286             builder.AppendCString(":");
287 
288             Handle<String> str = isolate->factory()->NumberToString(
289                 handle(Smi::FromInt(info.line + 1), isolate));
290             builder.AppendString(str);
291 
292             builder.AppendCString(":");
293 
294             str = isolate->factory()->NumberToString(
295                 handle(Smi::FromInt(info.column + 1), isolate));
296             builder.AppendString(str);
297           }
298         } else {
299           DCHECK(!eval_from_script->name().IsString());
300           builder.AppendCString("unknown source");
301         }
302       }
303     }
304     builder.AppendCString(")");
305   }
306 
307   Handle<String> result;
308   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
309   return result;
310 }
311 
312 }  // namespace
313 
GetEvalOrigin()314 Handle<PrimitiveHeapObject> StackFrameBase::GetEvalOrigin() {
315   if (!HasScript() || !IsEval()) return isolate_->factory()->undefined_value();
316   return FormatEvalOrigin(isolate_, GetScript()).ToHandleChecked();
317 }
318 
GetWasmModuleName()319 Handle<PrimitiveHeapObject> StackFrameBase::GetWasmModuleName() {
320   return isolate_->factory()->undefined_value();
321 }
322 
GetWasmFunctionIndex()323 int StackFrameBase::GetWasmFunctionIndex() { return StackFrameBase::kNone; }
324 
GetWasmInstance()325 Handle<HeapObject> StackFrameBase::GetWasmInstance() {
326   return isolate_->factory()->undefined_value();
327 }
328 
GetScriptId() const329 int StackFrameBase::GetScriptId() const {
330   if (!HasScript()) return kNone;
331   return GetScript()->id();
332 }
333 
IsEval()334 bool StackFrameBase::IsEval() {
335   return HasScript() &&
336          GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL;
337 }
338 
FromFrameArray(Isolate * isolate,Handle<FrameArray> array,int frame_ix)339 void JSStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
340                                   int frame_ix) {
341   DCHECK(!array->IsWasmFrame(frame_ix));
342   isolate_ = isolate;
343   receiver_ = handle(array->Receiver(frame_ix), isolate);
344   function_ = handle(array->Function(frame_ix), isolate);
345   code_ = handle(array->Code(frame_ix), isolate);
346   offset_ = array->Offset(frame_ix).value();
347   cached_position_ = base::nullopt;
348 
349   const int flags = array->Flags(frame_ix).value();
350   is_constructor_ = (flags & FrameArray::kIsConstructor) != 0;
351   is_strict_ = (flags & FrameArray::kIsStrict) != 0;
352   is_async_ = (flags & FrameArray::kIsAsync) != 0;
353   is_promise_all_ = (flags & FrameArray::kIsPromiseAll) != 0;
354   is_promise_any_ = (flags & FrameArray::kIsPromiseAny) != 0;
355 }
356 
JSStackFrame(Isolate * isolate,Handle<Object> receiver,Handle<JSFunction> function,Handle<AbstractCode> code,int offset)357 JSStackFrame::JSStackFrame(Isolate* isolate, Handle<Object> receiver,
358                            Handle<JSFunction> function,
359                            Handle<AbstractCode> code, int offset)
360     : StackFrameBase(isolate),
361       receiver_(receiver),
362       function_(function),
363       code_(code),
364       offset_(offset),
365       cached_position_(base::nullopt),
366       is_async_(false),
367       is_constructor_(false),
368       is_strict_(false) {}
369 
GetFunction() const370 Handle<Object> JSStackFrame::GetFunction() const {
371   return Handle<Object>::cast(function_);
372 }
373 
GetFileName()374 Handle<Object> JSStackFrame::GetFileName() {
375   if (!HasScript()) return isolate_->factory()->null_value();
376   return handle(GetScript()->name(), isolate_);
377 }
378 
GetFunctionName()379 Handle<PrimitiveHeapObject> JSStackFrame::GetFunctionName() {
380   Handle<String> result = JSFunction::GetDebugName(function_);
381   if (result->length() != 0) return result;
382 
383   if (HasScript() &&
384       GetScript()->compilation_type() == Script::COMPILATION_TYPE_EVAL) {
385     return isolate_->factory()->eval_string();
386   }
387   return isolate_->factory()->null_value();
388 }
389 
390 namespace {
391 
CheckMethodName(Isolate * isolate,Handle<JSReceiver> receiver,Handle<Name> name,Handle<JSFunction> fun,LookupIterator::Configuration config)392 bool CheckMethodName(Isolate* isolate, Handle<JSReceiver> receiver,
393                      Handle<Name> name, Handle<JSFunction> fun,
394                      LookupIterator::Configuration config) {
395   LookupIterator::Key key(isolate, name);
396   LookupIterator iter(isolate, receiver, key, config);
397   if (iter.state() == LookupIterator::DATA) {
398     return iter.GetDataValue().is_identical_to(fun);
399   } else if (iter.state() == LookupIterator::ACCESSOR) {
400     Handle<Object> accessors = iter.GetAccessors();
401     if (accessors->IsAccessorPair()) {
402       Handle<AccessorPair> pair = Handle<AccessorPair>::cast(accessors);
403       return pair->getter() == *fun || pair->setter() == *fun;
404     }
405   }
406   return false;
407 }
408 
ScriptNameOrSourceUrl(Handle<Script> script,Isolate * isolate)409 Handle<Object> ScriptNameOrSourceUrl(Handle<Script> script, Isolate* isolate) {
410   Object name_or_url = script->source_url();
411   if (!name_or_url.IsString()) name_or_url = script->name();
412   return handle(name_or_url, isolate);
413 }
414 
415 }  // namespace
416 
GetScriptNameOrSourceUrl()417 Handle<Object> JSStackFrame::GetScriptNameOrSourceUrl() {
418   if (!HasScript()) return isolate_->factory()->null_value();
419   return ScriptNameOrSourceUrl(GetScript(), isolate_);
420 }
421 
GetMethodName()422 Handle<PrimitiveHeapObject> JSStackFrame::GetMethodName() {
423   if (receiver_->IsNullOrUndefined(isolate_)) {
424     return isolate_->factory()->null_value();
425   }
426 
427   Handle<JSReceiver> receiver;
428   if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
429     DCHECK(isolate_->has_pending_exception());
430     isolate_->clear_pending_exception();
431     isolate_->set_external_caught_exception(false);
432     return isolate_->factory()->null_value();
433   }
434 
435   Handle<String> name(function_->shared().Name(), isolate_);
436   name = String::Flatten(isolate_, name);
437 
438   // The static initializer function is not a method, so don't add a
439   // class name, just return the function name.
440   if (name->HasOneBytePrefix(CStrVector("<static_fields_initializer>"))) {
441     return name;
442   }
443 
444   // ES2015 gives getters and setters name prefixes which must
445   // be stripped to find the property name.
446   if (name->HasOneBytePrefix(CStrVector("get ")) ||
447       name->HasOneBytePrefix(CStrVector("set "))) {
448     name = isolate_->factory()->NewProperSubString(name, 4, name->length());
449   }
450   if (CheckMethodName(isolate_, receiver, name, function_,
451                       LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR)) {
452     return name;
453   }
454 
455   HandleScope outer_scope(isolate_);
456   Handle<PrimitiveHeapObject> result;
457   for (PrototypeIterator iter(isolate_, receiver, kStartAtReceiver);
458        !iter.IsAtEnd(); iter.Advance()) {
459     Handle<Object> current = PrototypeIterator::GetCurrent(iter);
460     if (!current->IsJSObject()) break;
461     Handle<JSObject> current_obj = Handle<JSObject>::cast(current);
462     if (current_obj->IsAccessCheckNeeded()) break;
463     Handle<FixedArray> keys =
464         KeyAccumulator::GetOwnEnumPropertyKeys(isolate_, current_obj);
465     for (int i = 0; i < keys->length(); i++) {
466       HandleScope inner_scope(isolate_);
467       if (!keys->get(i).IsName()) continue;
468       Handle<Name> name_key(Name::cast(keys->get(i)), isolate_);
469       if (!CheckMethodName(isolate_, current_obj, name_key, function_,
470                            LookupIterator::OWN_SKIP_INTERCEPTOR))
471         continue;
472       // Return null in case of duplicates to avoid confusion.
473       if (!result.is_null()) return isolate_->factory()->null_value();
474       result = inner_scope.CloseAndEscape(name_key);
475     }
476   }
477 
478   if (!result.is_null()) return outer_scope.CloseAndEscape(result);
479   return isolate_->factory()->null_value();
480 }
481 
GetTypeName()482 Handle<PrimitiveHeapObject> JSStackFrame::GetTypeName() {
483   // TODO(jgruber): Check for strict/constructor here as in
484   // CallSitePrototypeGetThis.
485 
486   if (receiver_->IsNullOrUndefined(isolate_)) {
487     return isolate_->factory()->null_value();
488   } else if (receiver_->IsJSProxy()) {
489     return isolate_->factory()->Proxy_string();
490   }
491 
492   Handle<JSReceiver> receiver;
493   if (!Object::ToObject(isolate_, receiver_).ToHandle(&receiver)) {
494     DCHECK(isolate_->has_pending_exception());
495     isolate_->clear_pending_exception();
496     isolate_->set_external_caught_exception(false);
497     return isolate_->factory()->null_value();
498   }
499 
500   return JSReceiver::GetConstructorName(receiver);
501 }
502 
GetLineNumber()503 int JSStackFrame::GetLineNumber() {
504   DCHECK_LE(0, GetPosition());
505   if (HasScript()) return Script::GetLineNumber(GetScript(), GetPosition()) + 1;
506   return kNone;
507 }
508 
GetColumnNumber()509 int JSStackFrame::GetColumnNumber() {
510   DCHECK_LE(0, GetPosition());
511   if (HasScript()) {
512     return Script::GetColumnNumber(GetScript(), GetPosition()) + 1;
513   }
514   return kNone;
515 }
516 
GetPromiseIndex() const517 int JSStackFrame::GetPromiseIndex() const {
518   return (is_promise_all_ || is_promise_any_) ? offset_ : kNone;
519 }
520 
IsNative()521 bool JSStackFrame::IsNative() {
522   return HasScript() && GetScript()->type() == Script::TYPE_NATIVE;
523 }
524 
IsToplevel()525 bool JSStackFrame::IsToplevel() {
526   return receiver_->IsJSGlobalProxy() || receiver_->IsNullOrUndefined(isolate_);
527 }
528 
GetPosition() const529 int JSStackFrame::GetPosition() const {
530   if (cached_position_) return *cached_position_;
531 
532   Handle<SharedFunctionInfo> shared = handle(function_->shared(), isolate_);
533   SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate_, shared);
534   cached_position_ = code_->SourcePosition(offset_);
535   return *cached_position_;
536 }
537 
HasScript() const538 bool JSStackFrame::HasScript() const {
539   return function_->shared().script().IsScript();
540 }
541 
GetScript() const542 Handle<Script> JSStackFrame::GetScript() const {
543   return handle(Script::cast(function_->shared().script()), isolate_);
544 }
545 
FromFrameArray(Isolate * isolate,Handle<FrameArray> array,int frame_ix)546 void WasmStackFrame::FromFrameArray(Isolate* isolate, Handle<FrameArray> array,
547                                     int frame_ix) {
548   // This function is called for compiled and interpreted wasm frames, and for
549   // asm.js->wasm frames.
550   DCHECK(array->IsWasmFrame(frame_ix) ||
551          array->IsAsmJsWasmFrame(frame_ix));
552   isolate_ = isolate;
553   wasm_instance_ = handle(array->WasmInstance(frame_ix), isolate);
554   wasm_func_index_ = array->WasmFunctionIndex(frame_ix).value();
555   // The {WasmCode*} is held alive by the {GlobalWasmCodeRef}.
556   auto global_wasm_code_ref =
557       Managed<wasm::GlobalWasmCodeRef>::cast(array->WasmCodeObject(frame_ix));
558   code_ = global_wasm_code_ref.get()->code();
559   offset_ = array->Offset(frame_ix).value();
560 }
561 
GetReceiver() const562 Handle<Object> WasmStackFrame::GetReceiver() const { return wasm_instance_; }
563 
GetFunction() const564 Handle<Object> WasmStackFrame::GetFunction() const {
565   return handle(Smi::FromInt(wasm_func_index_), isolate_);
566 }
567 
GetFunctionName()568 Handle<PrimitiveHeapObject> WasmStackFrame::GetFunctionName() {
569   Handle<PrimitiveHeapObject> name;
570   Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
571                                          isolate_);
572   if (!WasmModuleObject::GetFunctionNameOrNull(isolate_, module_object,
573                                                wasm_func_index_)
574            .ToHandle(&name)) {
575     name = isolate_->factory()->null_value();
576   }
577   return name;
578 }
579 
GetScriptNameOrSourceUrl()580 Handle<Object> WasmStackFrame::GetScriptNameOrSourceUrl() {
581   Handle<Script> script = GetScript();
582   DCHECK_EQ(Script::TYPE_WASM, script->type());
583   return ScriptNameOrSourceUrl(script, isolate_);
584 }
585 
GetWasmModuleName()586 Handle<PrimitiveHeapObject> WasmStackFrame::GetWasmModuleName() {
587   Handle<PrimitiveHeapObject> module_name;
588   Handle<WasmModuleObject> module_object(wasm_instance_->module_object(),
589                                          isolate_);
590   if (!WasmModuleObject::GetModuleNameOrNull(isolate_, module_object)
591            .ToHandle(&module_name)) {
592     module_name = isolate_->factory()->null_value();
593   }
594   return module_name;
595 }
596 
GetWasmInstance()597 Handle<HeapObject> WasmStackFrame::GetWasmInstance() { return wasm_instance_; }
598 
GetPosition() const599 int WasmStackFrame::GetPosition() const {
600   return IsInterpreted() ? offset_ : code_->GetSourcePositionBefore(offset_);
601 }
602 
GetColumnNumber()603 int WasmStackFrame::GetColumnNumber() { return GetModuleOffset(); }
604 
GetModuleOffset() const605 int WasmStackFrame::GetModuleOffset() const {
606   const int function_offset =
607       GetWasmFunctionOffset(wasm_instance_->module(), wasm_func_index_);
608   return function_offset + GetPosition();
609 }
610 
GetFileName()611 Handle<Object> WasmStackFrame::GetFileName() { return Null(); }
612 
Null() const613 Handle<PrimitiveHeapObject> WasmStackFrame::Null() const {
614   return isolate_->factory()->null_value();
615 }
616 
HasScript() const617 bool WasmStackFrame::HasScript() const { return true; }
618 
GetScript() const619 Handle<Script> WasmStackFrame::GetScript() const {
620   return handle(wasm_instance_->module_object().script(), isolate_);
621 }
622 
FromFrameArray(Isolate * isolate,Handle<FrameArray> array,int frame_ix)623 void AsmJsWasmStackFrame::FromFrameArray(Isolate* isolate,
624                                          Handle<FrameArray> array,
625                                          int frame_ix) {
626   DCHECK(array->IsAsmJsWasmFrame(frame_ix));
627   WasmStackFrame::FromFrameArray(isolate, array, frame_ix);
628   is_at_number_conversion_ =
629       array->Flags(frame_ix).value() & FrameArray::kAsmJsAtNumberConversion;
630 }
631 
GetReceiver() const632 Handle<Object> AsmJsWasmStackFrame::GetReceiver() const {
633   return isolate_->global_proxy();
634 }
635 
GetFunction() const636 Handle<Object> AsmJsWasmStackFrame::GetFunction() const {
637   // TODO(clemensb): Return lazily created JSFunction.
638   return Null();
639 }
640 
GetFileName()641 Handle<Object> AsmJsWasmStackFrame::GetFileName() {
642   Handle<Script> script(wasm_instance_->module_object().script(), isolate_);
643   DCHECK(script->IsUserJavaScript());
644   return handle(script->name(), isolate_);
645 }
646 
GetScriptNameOrSourceUrl()647 Handle<Object> AsmJsWasmStackFrame::GetScriptNameOrSourceUrl() {
648   Handle<Script> script(wasm_instance_->module_object().script(), isolate_);
649   DCHECK_EQ(Script::TYPE_NORMAL, script->type());
650   return ScriptNameOrSourceUrl(script, isolate_);
651 }
652 
GetPosition() const653 int AsmJsWasmStackFrame::GetPosition() const {
654   DCHECK_LE(0, offset_);
655   int byte_offset = code_->GetSourcePositionBefore(offset_);
656   const wasm::WasmModule* module = wasm_instance_->module();
657   return GetSourcePosition(module, wasm_func_index_, byte_offset,
658                            is_at_number_conversion_);
659 }
660 
GetLineNumber()661 int AsmJsWasmStackFrame::GetLineNumber() {
662   DCHECK_LE(0, GetPosition());
663   Handle<Script> script(wasm_instance_->module_object().script(), isolate_);
664   DCHECK(script->IsUserJavaScript());
665   return Script::GetLineNumber(script, GetPosition()) + 1;
666 }
667 
GetColumnNumber()668 int AsmJsWasmStackFrame::GetColumnNumber() {
669   DCHECK_LE(0, GetPosition());
670   Handle<Script> script(wasm_instance_->module_object().script(), isolate_);
671   DCHECK(script->IsUserJavaScript());
672   return Script::GetColumnNumber(script, GetPosition()) + 1;
673 }
674 
FrameArrayIterator(Isolate * isolate,Handle<FrameArray> array,int frame_ix)675 FrameArrayIterator::FrameArrayIterator(Isolate* isolate,
676                                        Handle<FrameArray> array, int frame_ix)
677     : isolate_(isolate), array_(array), frame_ix_(frame_ix) {}
678 
HasFrame() const679 bool FrameArrayIterator::HasFrame() const {
680   return (frame_ix_ < array_->FrameCount());
681 }
682 
Advance()683 void FrameArrayIterator::Advance() { frame_ix_++; }
684 
Frame()685 StackFrameBase* FrameArrayIterator::Frame() {
686   DCHECK(HasFrame());
687   const int flags = array_->Flags(frame_ix_).value();
688   int flag_mask = FrameArray::kIsWasmFrame | FrameArray::kIsAsmJsWasmFrame;
689   switch (flags & flag_mask) {
690     case 0:
691       js_frame_.FromFrameArray(isolate_, array_, frame_ix_);
692       return &js_frame_;
693     case FrameArray::kIsWasmFrame:
694       wasm_frame_.FromFrameArray(isolate_, array_, frame_ix_);
695       return &wasm_frame_;
696     case FrameArray::kIsAsmJsWasmFrame:
697       asm_wasm_frame_.FromFrameArray(isolate_, array_, frame_ix_);
698       return &asm_wasm_frame_;
699     default:
700       UNREACHABLE();
701   }
702 }
703 
704 namespace {
705 
ConstructCallSite(Isolate * isolate,Handle<StackTraceFrame> frame)706 MaybeHandle<Object> ConstructCallSite(Isolate* isolate,
707                                       Handle<StackTraceFrame> frame) {
708   Handle<JSFunction> target =
709       handle(isolate->native_context()->callsite_function(), isolate);
710 
711   Handle<JSObject> obj;
712   ASSIGN_RETURN_ON_EXCEPTION(
713       isolate, obj,
714       JSObject::New(target, target, Handle<AllocationSite>::null()), Object);
715 
716   // TODO(szuend): Introduce a new symbol "call_site_frame_symbol" and set
717   //               it to the StackTraceFrame. The CallSite API builtins can then
718   //               be implemented using StackFrameInfo objects.
719 
720   Handle<FrameArray> frame_array(FrameArray::cast(frame->frame_array()),
721                                  isolate);
722   int frame_index = frame->frame_index();
723 
724   Handle<Symbol> key = isolate->factory()->call_site_frame_array_symbol();
725   RETURN_ON_EXCEPTION(isolate,
726                       JSObject::SetOwnPropertyIgnoreAttributes(
727                           obj, key, frame_array, DONT_ENUM),
728                       Object);
729 
730   key = isolate->factory()->call_site_frame_index_symbol();
731   Handle<Object> value(Smi::FromInt(frame_index), isolate);
732   RETURN_ON_EXCEPTION(
733       isolate,
734       JSObject::SetOwnPropertyIgnoreAttributes(obj, key, value, DONT_ENUM),
735       Object);
736 
737   return obj;
738 }
739 
740 // Convert the raw frames as written by Isolate::CaptureSimpleStackTrace into
741 // a JSArray of JSCallSite objects.
GetStackFrames(Isolate * isolate,Handle<FixedArray> elems)742 MaybeHandle<JSArray> GetStackFrames(Isolate* isolate,
743                                     Handle<FixedArray> elems) {
744   const int frame_count = elems->length();
745 
746   Handle<FixedArray> frames = isolate->factory()->NewFixedArray(frame_count);
747   for (int i = 0; i < frame_count; i++) {
748     Handle<Object> site;
749     Handle<StackTraceFrame> frame(StackTraceFrame::cast(elems->get(i)),
750                                   isolate);
751     ASSIGN_RETURN_ON_EXCEPTION(isolate, site, ConstructCallSite(isolate, frame),
752                                JSArray);
753     frames->set(i, *site);
754   }
755 
756   return isolate->factory()->NewJSArrayWithElements(frames);
757 }
758 
AppendErrorString(Isolate * isolate,Handle<Object> error,IncrementalStringBuilder * builder)759 MaybeHandle<Object> AppendErrorString(Isolate* isolate, Handle<Object> error,
760                                       IncrementalStringBuilder* builder) {
761   MaybeHandle<String> err_str =
762       ErrorUtils::ToString(isolate, Handle<Object>::cast(error));
763   if (err_str.is_null()) {
764     // Error.toString threw. Try to return a string representation of the thrown
765     // exception instead.
766 
767     DCHECK(isolate->has_pending_exception());
768     Handle<Object> pending_exception =
769         handle(isolate->pending_exception(), isolate);
770     isolate->clear_pending_exception();
771     isolate->set_external_caught_exception(false);
772 
773     err_str = ErrorUtils::ToString(isolate, pending_exception);
774     if (err_str.is_null()) {
775       // Formatting the thrown exception threw again, give up.
776       DCHECK(isolate->has_pending_exception());
777       isolate->clear_pending_exception();
778       isolate->set_external_caught_exception(false);
779       builder->AppendCString("<error>");
780     } else {
781       // Formatted thrown exception successfully, append it.
782       builder->AppendCString("<error: ");
783       builder->AppendString(err_str.ToHandleChecked());
784       builder->AppendCharacter('>');
785     }
786   } else {
787     builder->AppendString(err_str.ToHandleChecked());
788   }
789 
790   return error;
791 }
792 
793 class PrepareStackTraceScope {
794  public:
PrepareStackTraceScope(Isolate * isolate)795   explicit PrepareStackTraceScope(Isolate* isolate) : isolate_(isolate) {
796     DCHECK(!isolate_->formatting_stack_trace());
797     isolate_->set_formatting_stack_trace(true);
798   }
799 
~PrepareStackTraceScope()800   ~PrepareStackTraceScope() { isolate_->set_formatting_stack_trace(false); }
801 
802  private:
803   Isolate* isolate_;
804 
805   DISALLOW_COPY_AND_ASSIGN(PrepareStackTraceScope);
806 };
807 
808 }  // namespace
809 
810 // static
FormatStackTrace(Isolate * isolate,Handle<JSObject> error,Handle<Object> raw_stack)811 MaybeHandle<Object> ErrorUtils::FormatStackTrace(Isolate* isolate,
812                                                  Handle<JSObject> error,
813                                                  Handle<Object> raw_stack) {
814   DCHECK(raw_stack->IsFixedArray());
815   Handle<FixedArray> elems = Handle<FixedArray>::cast(raw_stack);
816 
817   const bool in_recursion = isolate->formatting_stack_trace();
818   if (!in_recursion) {
819     Handle<Context> error_context = error->GetCreationContext();
820     DCHECK(error_context->IsNativeContext());
821 
822     if (isolate->HasPrepareStackTraceCallback()) {
823       PrepareStackTraceScope scope(isolate);
824 
825       Handle<JSArray> sites;
826       ASSIGN_RETURN_ON_EXCEPTION(isolate, sites, GetStackFrames(isolate, elems),
827                                  Object);
828 
829       Handle<Object> result;
830       ASSIGN_RETURN_ON_EXCEPTION(
831           isolate, result,
832           isolate->RunPrepareStackTraceCallback(error_context, error, sites),
833           Object);
834       return result;
835     } else {
836       Handle<JSFunction> global_error =
837           handle(error_context->error_function(), isolate);
838 
839       // If there's a user-specified "prepareStackTrace" function, call it on
840       // the frames and use its result.
841 
842       Handle<Object> prepare_stack_trace;
843       ASSIGN_RETURN_ON_EXCEPTION(
844           isolate, prepare_stack_trace,
845           JSFunction::GetProperty(isolate, global_error, "prepareStackTrace"),
846           Object);
847 
848       if (prepare_stack_trace->IsJSFunction()) {
849         PrepareStackTraceScope scope(isolate);
850 
851         isolate->CountUsage(v8::Isolate::kErrorPrepareStackTrace);
852 
853         Handle<JSArray> sites;
854         ASSIGN_RETURN_ON_EXCEPTION(isolate, sites,
855                                    GetStackFrames(isolate, elems), Object);
856 
857         const int argc = 2;
858         ScopedVector<Handle<Object>> argv(argc);
859         argv[0] = error;
860         argv[1] = sites;
861 
862         Handle<Object> result;
863 
864         ASSIGN_RETURN_ON_EXCEPTION(
865             isolate, result,
866             Execution::Call(isolate, prepare_stack_trace, global_error, argc,
867                             argv.begin()),
868             Object);
869 
870         return result;
871       }
872     }
873   }
874 
875   // Otherwise, run our internal formatting logic.
876 
877   IncrementalStringBuilder builder(isolate);
878 
879   RETURN_ON_EXCEPTION(isolate, AppendErrorString(isolate, error, &builder),
880                       Object);
881 
882   wasm::WasmCodeRefScope wasm_code_ref_scope;
883 
884   for (int i = 0; i < elems->length(); ++i) {
885     builder.AppendCString("\n    at ");
886 
887     Handle<StackTraceFrame> frame(StackTraceFrame::cast(elems->get(i)),
888                                   isolate);
889     SerializeStackTraceFrame(isolate, frame, &builder);
890 
891     if (isolate->has_pending_exception()) {
892       // CallSite.toString threw. Parts of the current frame might have been
893       // stringified already regardless. Still, try to append a string
894       // representation of the thrown exception.
895 
896       Handle<Object> pending_exception =
897           handle(isolate->pending_exception(), isolate);
898       isolate->clear_pending_exception();
899       isolate->set_external_caught_exception(false);
900 
901       MaybeHandle<String> exception_string =
902           ErrorUtils::ToString(isolate, pending_exception);
903       if (exception_string.is_null()) {
904         // Formatting the thrown exception threw again, give up.
905 
906         builder.AppendCString("<error>");
907       } else {
908         // Formatted thrown exception successfully, append it.
909         builder.AppendCString("<error: ");
910         builder.AppendString(exception_string.ToHandleChecked());
911         builder.AppendCString("<error>");
912       }
913     }
914   }
915 
916   return builder.Finish();
917 }
918 
Format(Isolate * isolate,MessageTemplate index,Handle<Object> arg0,Handle<Object> arg1,Handle<Object> arg2)919 Handle<String> MessageFormatter::Format(Isolate* isolate, MessageTemplate index,
920                                         Handle<Object> arg0,
921                                         Handle<Object> arg1,
922                                         Handle<Object> arg2) {
923   Factory* factory = isolate->factory();
924   Handle<String> arg0_string = factory->empty_string();
925   if (!arg0.is_null()) {
926     arg0_string = Object::NoSideEffectsToString(isolate, arg0);
927   }
928   Handle<String> arg1_string = factory->empty_string();
929   if (!arg1.is_null()) {
930     arg1_string = Object::NoSideEffectsToString(isolate, arg1);
931   }
932   Handle<String> arg2_string = factory->empty_string();
933   if (!arg2.is_null()) {
934     arg2_string = Object::NoSideEffectsToString(isolate, arg2);
935   }
936   MaybeHandle<String> maybe_result_string = MessageFormatter::Format(
937       isolate, index, arg0_string, arg1_string, arg2_string);
938   Handle<String> result_string;
939   if (!maybe_result_string.ToHandle(&result_string)) {
940     DCHECK(isolate->has_pending_exception());
941     isolate->clear_pending_exception();
942     return factory->InternalizeString(StaticCharVector("<error>"));
943   }
944   // A string that has been obtained from JS code in this way is
945   // likely to be a complicated ConsString of some sort.  We flatten it
946   // here to improve the efficiency of converting it to a C string and
947   // other operations that are likely to take place (see GetLocalizedMessage
948   // for example).
949   return String::Flatten(isolate, result_string);
950 }
951 
TemplateString(MessageTemplate index)952 const char* MessageFormatter::TemplateString(MessageTemplate index) {
953   switch (index) {
954 #define CASE(NAME, STRING)       \
955   case MessageTemplate::k##NAME: \
956     return STRING;
957     MESSAGE_TEMPLATES(CASE)
958 #undef CASE
959     case MessageTemplate::kMessageCount:
960     default:
961       return nullptr;
962   }
963 }
964 
Format(Isolate * isolate,MessageTemplate index,Handle<String> arg0,Handle<String> arg1,Handle<String> arg2)965 MaybeHandle<String> MessageFormatter::Format(Isolate* isolate,
966                                              MessageTemplate index,
967                                              Handle<String> arg0,
968                                              Handle<String> arg1,
969                                              Handle<String> arg2) {
970   const char* template_string = TemplateString(index);
971   if (template_string == nullptr) {
972     isolate->ThrowIllegalOperation();
973     return MaybeHandle<String>();
974   }
975 
976   IncrementalStringBuilder builder(isolate);
977 
978   unsigned int i = 0;
979   Handle<String> args[] = {arg0, arg1, arg2};
980   for (const char* c = template_string; *c != '\0'; c++) {
981     if (*c == '%') {
982       // %% results in verbatim %.
983       if (*(c + 1) == '%') {
984         c++;
985         builder.AppendCharacter('%');
986       } else {
987         DCHECK(i < arraysize(args));
988         Handle<String> arg = args[i++];
989         builder.AppendString(arg);
990       }
991     } else {
992       builder.AppendCharacter(*c);
993     }
994   }
995 
996   return builder.Finish();
997 }
998 
Construct(Isolate * isolate,Handle<JSFunction> target,Handle<Object> new_target,Handle<Object> message)999 MaybeHandle<JSObject> ErrorUtils::Construct(Isolate* isolate,
1000                                             Handle<JSFunction> target,
1001                                             Handle<Object> new_target,
1002                                             Handle<Object> message) {
1003   FrameSkipMode mode = SKIP_FIRST;
1004   Handle<Object> caller;
1005 
1006   // When we're passed a JSFunction as new target, we can skip frames until that
1007   // specific function is seen instead of unconditionally skipping the first
1008   // frame.
1009   if (new_target->IsJSFunction()) {
1010     mode = SKIP_UNTIL_SEEN;
1011     caller = new_target;
1012   }
1013 
1014   return ErrorUtils::Construct(isolate, target, new_target, message, mode,
1015                                caller,
1016                                ErrorUtils::StackTraceCollection::kDetailed);
1017 }
1018 
Construct(Isolate * isolate,Handle<JSFunction> target,Handle<Object> new_target,Handle<Object> message,FrameSkipMode mode,Handle<Object> caller,StackTraceCollection stack_trace_collection)1019 MaybeHandle<JSObject> ErrorUtils::Construct(
1020     Isolate* isolate, Handle<JSFunction> target, Handle<Object> new_target,
1021     Handle<Object> message, FrameSkipMode mode, Handle<Object> caller,
1022     StackTraceCollection stack_trace_collection) {
1023   if (FLAG_correctness_fuzzer_suppressions) {
1024     // Abort range errors in correctness fuzzing, as their causes differ
1025     // accross correctness-fuzzing scenarios.
1026     if (target.is_identical_to(isolate->range_error_function())) {
1027       FATAL("Aborting on range error");
1028     }
1029     // Ignore error messages in correctness fuzzing, because the spec leaves
1030     // room for undefined behavior.
1031     message = isolate->factory()->InternalizeUtf8String(
1032         "Message suppressed for fuzzers (--correctness-fuzzer-suppressions)");
1033   }
1034 
1035   // 1. If NewTarget is undefined, let newTarget be the active function object,
1036   // else let newTarget be NewTarget.
1037   Handle<JSReceiver> new_target_recv =
1038       new_target->IsJSReceiver() ? Handle<JSReceiver>::cast(new_target)
1039                                  : Handle<JSReceiver>::cast(target);
1040 
1041   // 2. Let O be ? OrdinaryCreateFromConstructor(newTarget, "%ErrorPrototype%",
1042   //    « [[ErrorData]] »).
1043   Handle<JSObject> err;
1044   ASSIGN_RETURN_ON_EXCEPTION(
1045       isolate, err,
1046       JSObject::New(target, new_target_recv, Handle<AllocationSite>::null()),
1047       JSObject);
1048 
1049   // 3. If message is not undefined, then
1050   //  a. Let msg be ? ToString(message).
1051   //  b. Let msgDesc be the PropertyDescriptor{[[Value]]: msg, [[Writable]]:
1052   //     true, [[Enumerable]]: false, [[Configurable]]: true}.
1053   //  c. Perform ! DefinePropertyOrThrow(O, "message", msgDesc).
1054   // 4. Return O.
1055 
1056   if (!message->IsUndefined(isolate)) {
1057     Handle<String> msg_string;
1058     ASSIGN_RETURN_ON_EXCEPTION(isolate, msg_string,
1059                                Object::ToString(isolate, message), JSObject);
1060     RETURN_ON_EXCEPTION(
1061         isolate,
1062         JSObject::SetOwnPropertyIgnoreAttributes(
1063             err, isolate->factory()->message_string(), msg_string, DONT_ENUM),
1064         JSObject);
1065   }
1066 
1067   switch (stack_trace_collection) {
1068     case StackTraceCollection::kDetailed:
1069       RETURN_ON_EXCEPTION(
1070           isolate, isolate->CaptureAndSetDetailedStackTrace(err), JSObject);
1071       V8_FALLTHROUGH;
1072     case StackTraceCollection::kSimple:
1073       RETURN_ON_EXCEPTION(
1074           isolate, isolate->CaptureAndSetSimpleStackTrace(err, mode, caller),
1075           JSObject);
1076       break;
1077     case StackTraceCollection::kNone:
1078       break;
1079   }
1080   return err;
1081 }
1082 
1083 namespace {
1084 
GetStringPropertyOrDefault(Isolate * isolate,Handle<JSReceiver> recv,Handle<String> key,Handle<String> default_str)1085 MaybeHandle<String> GetStringPropertyOrDefault(Isolate* isolate,
1086                                                Handle<JSReceiver> recv,
1087                                                Handle<String> key,
1088                                                Handle<String> default_str) {
1089   Handle<Object> obj;
1090   ASSIGN_RETURN_ON_EXCEPTION(isolate, obj,
1091                              JSObject::GetProperty(isolate, recv, key), String);
1092 
1093   Handle<String> str;
1094   if (obj->IsUndefined(isolate)) {
1095     str = default_str;
1096   } else {
1097     ASSIGN_RETURN_ON_EXCEPTION(isolate, str, Object::ToString(isolate, obj),
1098                                String);
1099   }
1100 
1101   return str;
1102 }
1103 
1104 }  // namespace
1105 
1106 // ES6 section 19.5.3.4 Error.prototype.toString ( )
ToString(Isolate * isolate,Handle<Object> receiver)1107 MaybeHandle<String> ErrorUtils::ToString(Isolate* isolate,
1108                                          Handle<Object> receiver) {
1109   // 1. Let O be the this value.
1110   // 2. If Type(O) is not Object, throw a TypeError exception.
1111   if (!receiver->IsJSReceiver()) {
1112     return isolate->Throw<String>(isolate->factory()->NewTypeError(
1113         MessageTemplate::kIncompatibleMethodReceiver,
1114         isolate->factory()->NewStringFromAsciiChecked(
1115             "Error.prototype.toString"),
1116         receiver));
1117   }
1118   Handle<JSReceiver> recv = Handle<JSReceiver>::cast(receiver);
1119 
1120   // 3. Let name be ? Get(O, "name").
1121   // 4. If name is undefined, let name be "Error"; otherwise let name be
1122   // ? ToString(name).
1123   Handle<String> name_key = isolate->factory()->name_string();
1124   Handle<String> name_default = isolate->factory()->Error_string();
1125   Handle<String> name;
1126   ASSIGN_RETURN_ON_EXCEPTION(
1127       isolate, name,
1128       GetStringPropertyOrDefault(isolate, recv, name_key, name_default),
1129       String);
1130 
1131   // 5. Let msg be ? Get(O, "message").
1132   // 6. If msg is undefined, let msg be the empty String; otherwise let msg be
1133   // ? ToString(msg).
1134   Handle<String> msg_key = isolate->factory()->message_string();
1135   Handle<String> msg_default = isolate->factory()->empty_string();
1136   Handle<String> msg;
1137   ASSIGN_RETURN_ON_EXCEPTION(
1138       isolate, msg,
1139       GetStringPropertyOrDefault(isolate, recv, msg_key, msg_default), String);
1140 
1141   // 7. If name is the empty String, return msg.
1142   // 8. If msg is the empty String, return name.
1143   if (name->length() == 0) return msg;
1144   if (msg->length() == 0) return name;
1145 
1146   // 9. Return the result of concatenating name, the code unit 0x003A (COLON),
1147   // the code unit 0x0020 (SPACE), and msg.
1148   IncrementalStringBuilder builder(isolate);
1149   builder.AppendString(name);
1150   builder.AppendCString(": ");
1151   builder.AppendString(msg);
1152 
1153   Handle<String> result;
1154   ASSIGN_RETURN_ON_EXCEPTION(isolate, result, builder.Finish(), String);
1155   return result;
1156 }
1157 
1158 namespace {
1159 
DoFormatMessage(Isolate * isolate,MessageTemplate index,Handle<Object> arg0,Handle<Object> arg1,Handle<Object> arg2)1160 Handle<String> DoFormatMessage(Isolate* isolate, MessageTemplate index,
1161                                Handle<Object> arg0, Handle<Object> arg1,
1162                                Handle<Object> arg2) {
1163   Handle<String> arg0_str = Object::NoSideEffectsToString(isolate, arg0);
1164   Handle<String> arg1_str = Object::NoSideEffectsToString(isolate, arg1);
1165   Handle<String> arg2_str = Object::NoSideEffectsToString(isolate, arg2);
1166 
1167   isolate->native_context()->IncrementErrorsThrown();
1168 
1169   Handle<String> msg;
1170   if (!MessageFormatter::Format(isolate, index, arg0_str, arg1_str, arg2_str)
1171            .ToHandle(&msg)) {
1172     DCHECK(isolate->has_pending_exception());
1173     isolate->clear_pending_exception();
1174     isolate->set_external_caught_exception(false);
1175     return isolate->factory()->NewStringFromAsciiChecked("<error>");
1176   }
1177 
1178   return msg;
1179 }
1180 
1181 }  // namespace
1182 
1183 // static
MakeGenericError(Isolate * isolate,Handle<JSFunction> constructor,MessageTemplate index,Handle<Object> arg0,Handle<Object> arg1,Handle<Object> arg2,FrameSkipMode mode)1184 Handle<JSObject> ErrorUtils::MakeGenericError(
1185     Isolate* isolate, Handle<JSFunction> constructor, MessageTemplate index,
1186     Handle<Object> arg0, Handle<Object> arg1, Handle<Object> arg2,
1187     FrameSkipMode mode) {
1188   if (FLAG_clear_exceptions_on_js_entry) {
1189     // This function used to be implemented in JavaScript, and JSEntry
1190     // clears any pending exceptions - so whenever we'd call this from C++,
1191     // pending exceptions would be cleared. Preserve this behavior.
1192     isolate->clear_pending_exception();
1193   }
1194   Handle<String> msg = DoFormatMessage(isolate, index, arg0, arg1, arg2);
1195 
1196   DCHECK(mode != SKIP_UNTIL_SEEN);
1197 
1198   Handle<Object> no_caller;
1199   // The call below can't fail because constructor is a builtin.
1200   DCHECK(constructor->shared().HasBuiltinId());
1201   return ErrorUtils::Construct(isolate, constructor, constructor, msg, mode,
1202                                no_caller, StackTraceCollection::kDetailed)
1203       .ToHandleChecked();
1204 }
1205 
1206 namespace {
1207 
ComputeLocation(Isolate * isolate,MessageLocation * target)1208 bool ComputeLocation(Isolate* isolate, MessageLocation* target) {
1209   JavaScriptFrameIterator it(isolate);
1210   if (!it.done()) {
1211     // Compute the location from the function and the relocation info of the
1212     // baseline code. For optimized code this will use the deoptimization
1213     // information to get canonical location information.
1214     std::vector<FrameSummary> frames;
1215     it.frame()->Summarize(&frames);
1216     auto& summary = frames.back().AsJavaScript();
1217     Handle<SharedFunctionInfo> shared(summary.function()->shared(), isolate);
1218     Handle<Object> script(shared->script(), isolate);
1219     SharedFunctionInfo::EnsureSourcePositionsAvailable(isolate, shared);
1220     int pos = summary.abstract_code()->SourcePosition(summary.code_offset());
1221     if (script->IsScript() &&
1222         !(Handle<Script>::cast(script)->source().IsUndefined(isolate))) {
1223       Handle<Script> casted_script = Handle<Script>::cast(script);
1224       *target = MessageLocation(casted_script, pos, pos + 1, shared);
1225       return true;
1226     }
1227   }
1228   return false;
1229 }
1230 
BuildDefaultCallSite(Isolate * isolate,Handle<Object> object)1231 Handle<String> BuildDefaultCallSite(Isolate* isolate, Handle<Object> object) {
1232   IncrementalStringBuilder builder(isolate);
1233 
1234   builder.AppendString(Object::TypeOf(isolate, object));
1235   if (object->IsString()) {
1236     builder.AppendCString(" \"");
1237     Handle<String> string = Handle<String>::cast(object);
1238     // This threshold must be sufficiently far below String::kMaxLength that
1239     // the {builder}'s result can never exceed that limit.
1240     constexpr int kMaxPrintedStringLength = 100;
1241     if (string->length() <= kMaxPrintedStringLength) {
1242       builder.AppendString(string);
1243     } else {
1244       string = isolate->factory()->NewProperSubString(string, 0,
1245                                                       kMaxPrintedStringLength);
1246       builder.AppendString(string);
1247       builder.AppendCString("<...>");
1248     }
1249     builder.AppendCString("\"");
1250   } else if (object->IsNull(isolate)) {
1251     builder.AppendCString(" ");
1252     builder.AppendString(isolate->factory()->null_string());
1253   } else if (object->IsTrue(isolate)) {
1254     builder.AppendCString(" ");
1255     builder.AppendString(isolate->factory()->true_string());
1256   } else if (object->IsFalse(isolate)) {
1257     builder.AppendCString(" ");
1258     builder.AppendString(isolate->factory()->false_string());
1259   } else if (object->IsNumber()) {
1260     builder.AppendCString(" ");
1261     builder.AppendString(isolate->factory()->NumberToString(object));
1262   }
1263 
1264   return builder.Finish().ToHandleChecked();
1265 }
1266 
RenderCallSite(Isolate * isolate,Handle<Object> object,MessageLocation * location,CallPrinter::ErrorHint * hint)1267 Handle<String> RenderCallSite(Isolate* isolate, Handle<Object> object,
1268                               MessageLocation* location,
1269                               CallPrinter::ErrorHint* hint) {
1270   if (ComputeLocation(isolate, location)) {
1271     UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
1272         isolate, *location->shared());
1273     UnoptimizedCompileState compile_state(isolate);
1274     ParseInfo info(isolate, flags, &compile_state);
1275     if (parsing::ParseAny(&info, location->shared(), isolate,
1276                           parsing::ReportStatisticsMode::kNo)) {
1277       info.ast_value_factory()->Internalize(isolate);
1278       CallPrinter printer(isolate, location->shared()->IsUserJavaScript());
1279       Handle<String> str = printer.Print(info.literal(), location->start_pos());
1280       *hint = printer.GetErrorHint();
1281       if (str->length() > 0) return str;
1282     }
1283   }
1284   return BuildDefaultCallSite(isolate, object);
1285 }
1286 
UpdateErrorTemplate(CallPrinter::ErrorHint hint,MessageTemplate default_id)1287 MessageTemplate UpdateErrorTemplate(CallPrinter::ErrorHint hint,
1288                                     MessageTemplate default_id) {
1289   switch (hint) {
1290     case CallPrinter::ErrorHint::kNormalIterator:
1291       return MessageTemplate::kNotIterable;
1292 
1293     case CallPrinter::ErrorHint::kCallAndNormalIterator:
1294       return MessageTemplate::kNotCallableOrIterable;
1295 
1296     case CallPrinter::ErrorHint::kAsyncIterator:
1297       return MessageTemplate::kNotAsyncIterable;
1298 
1299     case CallPrinter::ErrorHint::kCallAndAsyncIterator:
1300       return MessageTemplate::kNotCallableOrAsyncIterable;
1301 
1302     case CallPrinter::ErrorHint::kNone:
1303       return default_id;
1304   }
1305 }
1306 
1307 }  // namespace
1308 
NewIteratorError(Isolate * isolate,Handle<Object> source)1309 Handle<JSObject> ErrorUtils::NewIteratorError(Isolate* isolate,
1310                                               Handle<Object> source) {
1311   MessageLocation location;
1312   CallPrinter::ErrorHint hint = CallPrinter::kNone;
1313   Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
1314   MessageTemplate id = MessageTemplate::kNotIterableNoSymbolLoad;
1315 
1316   if (hint == CallPrinter::kNone) {
1317     Handle<Symbol> iterator_symbol = isolate->factory()->iterator_symbol();
1318     return isolate->factory()->NewTypeError(id, callsite, iterator_symbol);
1319   }
1320 
1321   id = UpdateErrorTemplate(hint, id);
1322   return isolate->factory()->NewTypeError(id, callsite);
1323 }
1324 
ThrowSpreadArgError(Isolate * isolate,MessageTemplate id,Handle<Object> object)1325 Object ErrorUtils::ThrowSpreadArgError(Isolate* isolate, MessageTemplate id,
1326                                        Handle<Object> object) {
1327   MessageLocation location;
1328   Handle<String> callsite;
1329   if (ComputeLocation(isolate, &location)) {
1330     UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
1331         isolate, *location.shared());
1332     UnoptimizedCompileState compile_state(isolate);
1333     ParseInfo info(isolate, flags, &compile_state);
1334     if (parsing::ParseAny(&info, location.shared(), isolate,
1335                           parsing::ReportStatisticsMode::kNo)) {
1336       info.ast_value_factory()->Internalize(isolate);
1337       CallPrinter printer(isolate, location.shared()->IsUserJavaScript(),
1338                           CallPrinter::SpreadErrorInArgsHint::kErrorInArgs);
1339       Handle<String> str = printer.Print(info.literal(), location.start_pos());
1340       callsite =
1341           str->length() > 0 ? str : BuildDefaultCallSite(isolate, object);
1342 
1343       if (printer.spread_arg() != nullptr) {
1344         // Change the message location to point at the property name.
1345         int pos = printer.spread_arg()->position();
1346         location =
1347             MessageLocation(location.script(), pos, pos + 1, location.shared());
1348       }
1349     } else {
1350       callsite = BuildDefaultCallSite(isolate, object);
1351     }
1352   }
1353 
1354   isolate->ThrowAt(isolate->factory()->NewTypeError(id, callsite, object),
1355                    &location);
1356   return ReadOnlyRoots(isolate).exception();
1357 }
1358 
NewCalledNonCallableError(Isolate * isolate,Handle<Object> source)1359 Handle<JSObject> ErrorUtils::NewCalledNonCallableError(Isolate* isolate,
1360                                                        Handle<Object> source) {
1361   MessageLocation location;
1362   CallPrinter::ErrorHint hint = CallPrinter::kNone;
1363   Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
1364   MessageTemplate id = MessageTemplate::kCalledNonCallable;
1365   id = UpdateErrorTemplate(hint, id);
1366   return isolate->factory()->NewTypeError(id, callsite);
1367 }
1368 
NewConstructedNonConstructable(Isolate * isolate,Handle<Object> source)1369 Handle<JSObject> ErrorUtils::NewConstructedNonConstructable(
1370     Isolate* isolate, Handle<Object> source) {
1371   MessageLocation location;
1372   CallPrinter::ErrorHint hint = CallPrinter::kNone;
1373   Handle<String> callsite = RenderCallSite(isolate, source, &location, &hint);
1374   MessageTemplate id = MessageTemplate::kNotConstructor;
1375   return isolate->factory()->NewTypeError(id, callsite);
1376 }
1377 
ThrowLoadFromNullOrUndefined(Isolate * isolate,Handle<Object> object,MaybeHandle<Object> key)1378 Object ErrorUtils::ThrowLoadFromNullOrUndefined(Isolate* isolate,
1379                                                 Handle<Object> object,
1380                                                 MaybeHandle<Object> key) {
1381   DCHECK(object->IsNullOrUndefined());
1382 
1383   MaybeHandle<String> maybe_property_name;
1384 
1385   // Try to extract the property name from the given key, if any.
1386   Handle<Object> key_handle;
1387   if (key.ToHandle(&key_handle)) {
1388     if (key_handle->IsString()) {
1389       maybe_property_name = Handle<String>::cast(key_handle);
1390     }
1391   }
1392 
1393   Handle<String> callsite;
1394 
1395   // Inline the RenderCallSite logic here so that we can additonally access the
1396   // destructuring property.
1397   bool location_computed = false;
1398   bool is_destructuring = false;
1399   MessageLocation location;
1400   if (ComputeLocation(isolate, &location)) {
1401     location_computed = true;
1402 
1403     UnoptimizedCompileFlags flags = UnoptimizedCompileFlags::ForFunctionCompile(
1404         isolate, *location.shared());
1405     UnoptimizedCompileState compile_state(isolate);
1406     ParseInfo info(isolate, flags, &compile_state);
1407     if (parsing::ParseAny(&info, location.shared(), isolate,
1408                           parsing::ReportStatisticsMode::kNo)) {
1409       info.ast_value_factory()->Internalize(isolate);
1410       CallPrinter printer(isolate, location.shared()->IsUserJavaScript());
1411       Handle<String> str = printer.Print(info.literal(), location.start_pos());
1412 
1413       int pos = -1;
1414       is_destructuring = printer.destructuring_assignment() != nullptr;
1415 
1416       if (is_destructuring) {
1417         // If we don't have one yet, try to extract the property name from the
1418         // destructuring property in the AST.
1419         ObjectLiteralProperty* destructuring_prop =
1420             printer.destructuring_prop();
1421         if (maybe_property_name.is_null() && destructuring_prop != nullptr &&
1422             destructuring_prop->key()->IsPropertyName()) {
1423           maybe_property_name = destructuring_prop->key()
1424                                     ->AsLiteral()
1425                                     ->AsRawPropertyName()
1426                                     ->string();
1427           // Change the message location to point at the property name.
1428           pos = destructuring_prop->key()->position();
1429         }
1430         if (maybe_property_name.is_null()) {
1431           // Change the message location to point at the destructured value.
1432           pos = printer.destructuring_assignment()->value()->position();
1433         }
1434 
1435         // If we updated the pos to a valid pos, rewrite the location.
1436         if (pos != -1) {
1437           location = MessageLocation(location.script(), pos, pos + 1,
1438                                      location.shared());
1439         }
1440       }
1441 
1442       if (str->length() > 0) callsite = str;
1443     }
1444   }
1445 
1446   if (callsite.is_null()) {
1447     callsite = BuildDefaultCallSite(isolate, object);
1448   }
1449 
1450   Handle<JSObject> error;
1451   Handle<String> property_name;
1452   if (is_destructuring) {
1453     if (maybe_property_name.ToHandle(&property_name)) {
1454       error = isolate->factory()->NewTypeError(
1455           MessageTemplate::kNonCoercibleWithProperty, property_name, callsite,
1456           object);
1457     } else {
1458       error = isolate->factory()->NewTypeError(MessageTemplate::kNonCoercible,
1459                                                callsite, object);
1460     }
1461   } else {
1462     Handle<Object> key_handle;
1463     if (!key.ToHandle(&key_handle)) {
1464       key_handle = ReadOnlyRoots(isolate).undefined_value_handle();
1465     }
1466     if (*key_handle == ReadOnlyRoots(isolate).iterator_symbol()) {
1467       error = NewIteratorError(isolate, object);
1468     } else {
1469       error = isolate->factory()->NewTypeError(
1470           MessageTemplate::kNonObjectPropertyLoad, key_handle, object);
1471     }
1472   }
1473 
1474   if (location_computed) {
1475     isolate->ThrowAt(error, &location);
1476   } else {
1477     isolate->Throw(*error);
1478   }
1479   return ReadOnlyRoots(isolate).exception();
1480 }
1481 
1482 }  // namespace internal
1483 }  // namespace v8
1484