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